@thru/passkey 0.2.20 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/add-device.cjs +118 -0
- package/dist/auth/add-device.cjs.map +1 -0
- package/dist/auth/add-device.d.cts +69 -0
- package/dist/auth/add-device.d.ts +69 -0
- package/dist/auth/add-device.js +7 -0
- package/dist/auth/add-device.js.map +1 -0
- package/dist/auth.cjs +100 -6
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +2 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +10 -4
- package/dist/auth.js.map +1 -1
- package/dist/{chunk-75G2FPYW.js → chunk-OULTQZT7.js} +4 -3
- package/dist/chunk-OULTQZT7.js.map +1 -0
- package/dist/chunk-QAQNRQ7G.js +104 -0
- package/dist/chunk-QAQNRQ7G.js.map +1 -0
- package/dist/{chunk-B5SN7AS7.js → chunk-TW7HANJM.js} +99 -49
- package/dist/chunk-TW7HANJM.js.map +1 -0
- package/dist/{chunk-2JHC7OOH.js → chunk-ZNBMADOM.js} +2 -2
- package/dist/chunk-ZNBMADOM.js.map +1 -0
- package/dist/index.cjs +102 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -2
- package/dist/mobile.cjs +2 -2
- package/dist/mobile.cjs.map +1 -1
- package/dist/mobile.d.cts +2 -2
- package/dist/mobile.d.ts +2 -2
- package/dist/mobile.js +2 -2
- package/dist/mobile.js.map +1 -1
- package/dist/popup.cjs +3 -2
- package/dist/popup.cjs.map +1 -1
- package/dist/popup.d.cts +3 -3
- package/dist/popup.d.ts +3 -3
- package/dist/popup.js +1 -1
- package/dist/server.cjs +30 -60
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +32 -62
- package/dist/server.js.map +1 -1
- package/dist/{types-_HRzmn-j.d.cts → types-BTTlCVrw.d.cts} +25 -2
- package/dist/{types-_HRzmn-j.d.ts → types-BTTlCVrw.d.ts} +25 -2
- package/dist/web.cjs +99 -48
- package/dist/web.cjs.map +1 -1
- package/dist/web.d.cts +14 -7
- package/dist/web.d.ts +14 -7
- package/dist/web.js +3 -1
- package/package.json +11 -6
- package/src/auth/add-device.ts +213 -0
- package/src/auth/execute-tx.ts +1 -1
- package/src/auth/index.ts +11 -0
- package/src/auth/use-passkey-auth.ts +4 -2
- package/src/capabilities.ts +2 -1
- package/src/index.ts +4 -0
- package/src/label.test.ts +21 -0
- package/src/label.ts +14 -0
- package/src/mobile/index.ts +1 -1
- package/src/mobile/passkey.ts +1 -1
- package/src/mobile/storage.ts +1 -1
- package/src/mobile/types.ts +2 -2
- package/src/popup-service.ts +2 -1
- package/src/register.ts +23 -8
- package/src/server/challenge.ts +2 -2
- package/src/server/create-wallet.test.ts +2 -2
- package/src/server/create-wallet.ts +24 -16
- package/src/server/submit.test.ts +2 -2
- package/src/server/submit.ts +25 -4
- package/src/server/types.ts +2 -2
- package/src/server/utils.ts +1 -1
- package/src/sign.ts +127 -37
- package/src/types.ts +27 -2
- package/src/web.ts +6 -2
- package/tsconfig.json +3 -2
- package/tsup.config.ts +1 -0
- package/dist/chunk-2JHC7OOH.js.map +0 -1
- package/dist/chunk-75G2FPYW.js.map +0 -1
- package/dist/chunk-B5SN7AS7.js.map +0 -1
package/dist/server.js
CHANGED
|
@@ -9,59 +9,10 @@ import {
|
|
|
9
9
|
deriveWalletAddress,
|
|
10
10
|
encodeCreateInstruction,
|
|
11
11
|
encodeRegisterCredentialInstruction
|
|
12
|
-
} from "@thru/passkey-manager";
|
|
13
|
-
|
|
14
|
-
// ../helpers/src/constants.ts
|
|
15
|
-
var BASE64_URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
16
|
-
var tempMap = new Int16Array(256).fill(-1);
|
|
17
|
-
for (let i = 0; i < BASE64_URL_ALPHABET.length; i++) {
|
|
18
|
-
tempMap[BASE64_URL_ALPHABET.charCodeAt(i)] = i;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// ../helpers/src/address.ts
|
|
22
|
-
function encodeAddress(bytes) {
|
|
23
|
-
if (bytes.length !== 32) {
|
|
24
|
-
throw new Error("Expected 32-byte address");
|
|
25
|
-
}
|
|
26
|
-
let checksum = 0;
|
|
27
|
-
let accumulator = 0;
|
|
28
|
-
let bitsCollected = 0;
|
|
29
|
-
const output = ["t", "a"];
|
|
30
|
-
for (let i = 0; i < 30; i++) {
|
|
31
|
-
const byte = bytes[i];
|
|
32
|
-
checksum += byte;
|
|
33
|
-
accumulator = (accumulator << 8 | byte) >>> 0;
|
|
34
|
-
bitsCollected += 8;
|
|
35
|
-
while (bitsCollected >= 6) {
|
|
36
|
-
const index = accumulator >> bitsCollected - 6 & 63;
|
|
37
|
-
output.push(BASE64_URL_ALPHABET[index]);
|
|
38
|
-
bitsCollected -= 6;
|
|
39
|
-
accumulator &= maskForBits(bitsCollected);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const secondLast = bytes[30];
|
|
43
|
-
checksum += secondLast;
|
|
44
|
-
accumulator = (accumulator << 8 | secondLast) >>> 0;
|
|
45
|
-
bitsCollected += 8;
|
|
46
|
-
const last = bytes[31];
|
|
47
|
-
checksum += last;
|
|
48
|
-
accumulator = (accumulator << 8 | last) >>> 0;
|
|
49
|
-
bitsCollected += 8;
|
|
50
|
-
accumulator = (accumulator << 8 | checksum & 255) >>> 0;
|
|
51
|
-
bitsCollected += 8;
|
|
52
|
-
while (bitsCollected >= 6) {
|
|
53
|
-
const index = accumulator >> bitsCollected - 6 & 63;
|
|
54
|
-
output.push(BASE64_URL_ALPHABET[index]);
|
|
55
|
-
bitsCollected -= 6;
|
|
56
|
-
accumulator &= maskForBits(bitsCollected);
|
|
57
|
-
}
|
|
58
|
-
return output.join("");
|
|
59
|
-
}
|
|
60
|
-
function maskForBits(bits) {
|
|
61
|
-
return bits === 0 ? 0 : (1 << bits) - 1;
|
|
62
|
-
}
|
|
12
|
+
} from "@thru/programs/passkey-manager";
|
|
63
13
|
|
|
64
14
|
// src/server/utils.ts
|
|
15
|
+
import { encodeAddress } from "@thru/sdk/helpers";
|
|
65
16
|
var feePayerQueueSymbol = /* @__PURE__ */ Symbol.for("thru.sharedFeePayerQueues");
|
|
66
17
|
function getFeePayerQueues() {
|
|
67
18
|
const globalQueues = globalThis;
|
|
@@ -154,7 +105,10 @@ async function withSerializedFeePayer(feePayerPublicKey, work) {
|
|
|
154
105
|
async function createPasskeyWallet(opts) {
|
|
155
106
|
const walletName = opts.walletName ?? "default";
|
|
156
107
|
const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);
|
|
157
|
-
const walletBytes = await deriveWalletAddress(
|
|
108
|
+
const walletBytes = await deriveWalletAddress(
|
|
109
|
+
seed,
|
|
110
|
+
PASSKEY_MANAGER_PROGRAM_ADDRESS
|
|
111
|
+
);
|
|
158
112
|
const walletAddress = toThruAddress(walletBytes);
|
|
159
113
|
await withSerializedFeePayer(opts.adminPublicKey, async () => {
|
|
160
114
|
let walletExists = false;
|
|
@@ -207,7 +161,6 @@ async function createPasskeyWallet(opts) {
|
|
|
207
161
|
const credentialIdBytes = base64UrlToBytes(opts.credentialId);
|
|
208
162
|
const lookupAddressBytes = await deriveCredentialLookupAddress(
|
|
209
163
|
credentialIdBytes,
|
|
210
|
-
walletName,
|
|
211
164
|
PASSKEY_MANAGER_PROGRAM_ADDRESS
|
|
212
165
|
);
|
|
213
166
|
const lookupAddress = toThruAddress(lookupAddressBytes);
|
|
@@ -222,7 +175,7 @@ async function createPasskeyWallet(opts) {
|
|
|
222
175
|
lookupExists = false;
|
|
223
176
|
}
|
|
224
177
|
if (lookupExists) return;
|
|
225
|
-
const credSeed = await createCredentialLookupSeed(credentialIdBytes
|
|
178
|
+
const credSeed = await createCredentialLookupSeed(credentialIdBytes);
|
|
226
179
|
const stateProof = await getStateProof(opts.client, lookupAddress);
|
|
227
180
|
const accountCtx = buildAccountContext({
|
|
228
181
|
walletAddress,
|
|
@@ -248,7 +201,9 @@ async function createPasskeyWallet(opts) {
|
|
|
248
201
|
header: { fee: 0n }
|
|
249
202
|
});
|
|
250
203
|
await transaction.sign(opts.adminPrivateKey);
|
|
251
|
-
const signature = await opts.client.transactions.send(
|
|
204
|
+
const signature = await opts.client.transactions.send(
|
|
205
|
+
transaction.toWire()
|
|
206
|
+
);
|
|
252
207
|
const result = await trackTransaction(opts.client, signature, 6e4);
|
|
253
208
|
if (result.status !== "finalized") {
|
|
254
209
|
throw new Error(
|
|
@@ -271,7 +226,7 @@ import {
|
|
|
271
226
|
bytesToBase64Url,
|
|
272
227
|
createValidateChallenge,
|
|
273
228
|
fetchWalletNonce
|
|
274
|
-
} from "@thru/passkey-manager";
|
|
229
|
+
} from "@thru/programs/passkey-manager";
|
|
275
230
|
async function createPasskeyChallenge(opts) {
|
|
276
231
|
const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);
|
|
277
232
|
const challenge = await createValidateChallenge(
|
|
@@ -290,16 +245,31 @@ import {
|
|
|
290
245
|
PASSKEY_MANAGER_PROGRAM_ADDRESS as PASSKEY_MANAGER_PROGRAM_ADDRESS2,
|
|
291
246
|
concatenateInstructions,
|
|
292
247
|
encodeValidateInstruction,
|
|
293
|
-
hexToBytes
|
|
294
|
-
} from "@thru/passkey-manager";
|
|
248
|
+
hexToBytes
|
|
249
|
+
} from "@thru/programs/passkey-manager";
|
|
250
|
+
function base64ToBytes(base64) {
|
|
251
|
+
const globalBuffer = globalThis.Buffer;
|
|
252
|
+
if (globalBuffer) {
|
|
253
|
+
return globalBuffer.from(base64, "base64");
|
|
254
|
+
}
|
|
255
|
+
if (typeof atob === "function") {
|
|
256
|
+
const binary = atob(base64);
|
|
257
|
+
const bytes = new Uint8Array(binary.length);
|
|
258
|
+
for (let i = 0; i < binary.length; i++) {
|
|
259
|
+
bytes[i] = binary.charCodeAt(i);
|
|
260
|
+
}
|
|
261
|
+
return bytes;
|
|
262
|
+
}
|
|
263
|
+
throw new Error("Base64 decoding is not supported in this environment");
|
|
264
|
+
}
|
|
295
265
|
async function buildPasskeyTransaction(opts) {
|
|
296
266
|
const validateIx = encodeValidateInstruction({
|
|
297
267
|
walletAccountIdx: opts.accountCtx.walletAccountIdx,
|
|
298
268
|
authIdx: 0,
|
|
299
|
-
signatureR:
|
|
300
|
-
signatureS:
|
|
301
|
-
authenticatorData:
|
|
302
|
-
clientDataJSON:
|
|
269
|
+
signatureR: hexToBytes(opts.signatureR),
|
|
270
|
+
signatureS: hexToBytes(opts.signatureS),
|
|
271
|
+
authenticatorData: base64ToBytes(opts.authenticatorData),
|
|
272
|
+
clientDataJSON: base64ToBytes(opts.clientDataJSON)
|
|
303
273
|
});
|
|
304
274
|
const instructionData = concatenateInstructions([validateIx, opts.invokeIx]);
|
|
305
275
|
const transaction = await opts.client.transactions.build({
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/create-wallet.ts","../../helpers/src/constants.ts","../../helpers/src/address.ts","../src/server/utils.ts","../src/server/challenge.ts","../src/server/submit.ts","../src/server/handlers.ts"],"sourcesContent":["import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n base64UrlToBytes,\n buildAccountContext,\n createCredentialLookupSeed,\n createWalletSeed,\n deriveCredentialLookupAddress,\n deriveWalletAddress,\n encodeCreateInstruction,\n encodeRegisterCredentialInstruction,\n} from '@thru/passkey-manager';\nimport {\n toThruAddress,\n getStateProof,\n trackTransaction,\n withSerializedFeePayer,\n} from './utils';\nimport type { ThruClient } from './types';\n\nexport async function createPasskeyWallet(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n adminAddress: string;\n pubkeyX: Uint8Array;\n pubkeyY: Uint8Array;\n credentialId?: string;\n walletName?: string;\n}): Promise<{ walletAddress: string; credentialLookupAddress?: string }> {\n const walletName = opts.walletName ?? 'default';\n const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);\n const walletBytes = await deriveWalletAddress(seed, PASSKEY_MANAGER_PROGRAM_ADDRESS);\n const walletAddress = toThruAddress(walletBytes);\n\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let walletExists = false;\n try {\n await opts.client.accounts.get(walletAddress);\n walletExists = true;\n } catch {\n walletExists = false;\n }\n\n if (walletExists) return;\n\n const stateProof = await getStateProof(opts.client, walletAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const createIx = encodeCreateInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n authority: {\n tag: 1,\n pubkeyX: opts.pubkeyX,\n pubkeyY: opts.pubkeyY,\n },\n seed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: createIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(transaction.toWire());\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== 'finalized') {\n throw new Error(\n `Wallet creation failed with status: ${result.status}${\n result.errorCode !== undefined ? ` (error code: ${result.errorCode})` : ''\n }`\n );\n }\n });\n\n let credentialLookupAddress: string | undefined;\n if (opts.credentialId) {\n const credentialIdBytes = base64UrlToBytes(opts.credentialId);\n const lookupAddressBytes = await deriveCredentialLookupAddress(\n credentialIdBytes,\n walletName,\n PASSKEY_MANAGER_PROGRAM_ADDRESS\n );\n const lookupAddress = toThruAddress(lookupAddressBytes);\n\n credentialLookupAddress = lookupAddress;\n\n try {\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let lookupExists = false;\n try {\n await opts.client.accounts.get(lookupAddress);\n lookupExists = true;\n } catch {\n lookupExists = false;\n }\n\n if (lookupExists) return;\n\n const credSeed = await createCredentialLookupSeed(credentialIdBytes, walletName);\n const stateProof = await getStateProof(opts.client, lookupAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [lookupAddressBytes],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const registerIx = encodeRegisterCredentialInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n lookupAccountIdx: accountCtx.getAccountIndex(lookupAddressBytes),\n seed: credSeed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: registerIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(transaction.toWire());\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== 'finalized') {\n throw new Error(\n `Credential registration failed with status: ${result.status}${\n result.errorCode !== undefined ? ` (error code: ${result.errorCode})` : ''\n }`\n );\n }\n });\n } catch (error) {\n console.warn('Credential registration failed (non-fatal):', error);\n }\n }\n\n return {\n walletAddress,\n credentialLookupAddress,\n };\n}\n","export const BASE64_URL_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\nconst tempMap = new Int16Array(256).fill(-1);\nfor (let i = 0; i < BASE64_URL_ALPHABET.length; i++) {\n tempMap[BASE64_URL_ALPHABET.charCodeAt(i)] = i;\n}\nexport const BASE64_URL_MAP = tempMap\n\n","import { BASE64_URL_ALPHABET, BASE64_URL_MAP } from \"./constants\";\n\nexport function encodeAddress(bytes: Uint8Array): string {\n if (bytes.length !== 32) {\n throw new Error('Expected 32-byte address');\n }\n\n let checksum = 0;\n let accumulator = 0;\n let bitsCollected = 0;\n const output: string[] = ['t', 'a'];\n\n for (let i = 0; i < 30; i++) {\n const byte = bytes[i];\n checksum += byte;\n accumulator = ((accumulator << 8) | byte) >>> 0;\n bitsCollected += 8;\n while (bitsCollected >= 6) {\n const index = (accumulator >> (bitsCollected - 6)) & 0x3f;\n output.push(BASE64_URL_ALPHABET[index]);\n bitsCollected -= 6;\n accumulator &= maskForBits(bitsCollected);\n }\n }\n\n const secondLast = bytes[30];\n checksum += secondLast;\n accumulator = ((accumulator << 8) | secondLast) >>> 0;\n bitsCollected += 8;\n\n const last = bytes[31];\n checksum += last;\n accumulator = ((accumulator << 8) | last) >>> 0;\n bitsCollected += 8;\n\n accumulator = ((accumulator << 8) | (checksum & 0xff)) >>> 0;\n bitsCollected += 8;\n\n while (bitsCollected >= 6) {\n const index = (accumulator >> (bitsCollected - 6)) & 0x3f;\n output.push(BASE64_URL_ALPHABET[index]);\n bitsCollected -= 6;\n accumulator &= maskForBits(bitsCollected);\n }\n\n return output.join('');\n}\n\nexport function decodeAddress(value: string): Uint8Array {\n if (value.length !== 46) {\n throw new Error('Invalid address length');\n }\n if (!value.startsWith('ta')) {\n throw new Error('Address must start with \"ta\"');\n }\n\n const output = new Uint8Array(32);\n let checksum = 0;\n let inIdx = 2;\n let remaining = 40;\n let outIdx = 0;\n\n while (remaining >= 4) {\n const a = BASE64_URL_MAP[value.charCodeAt(inIdx)];\n const b = BASE64_URL_MAP[value.charCodeAt(inIdx + 1)];\n const c = BASE64_URL_MAP[value.charCodeAt(inIdx + 2)];\n const d = BASE64_URL_MAP[value.charCodeAt(inIdx + 3)];\n if (a < 0 || b < 0 || c < 0 || d < 0) {\n throw new Error('Invalid address encoding');\n }\n const triple = (a << 18) | (b << 12) | (c << 6) | d;\n const byte1 = (triple >> 16) & 0xff;\n const byte2 = (triple >> 8) & 0xff;\n const byte3 = triple & 0xff;\n checksum += byte1;\n checksum += byte2;\n checksum += byte3;\n output[outIdx++] = byte1;\n output[outIdx++] = byte2;\n output[outIdx++] = byte3;\n inIdx += 4;\n remaining -= 4;\n }\n\n const a = BASE64_URL_MAP[value.charCodeAt(inIdx)];\n const b = BASE64_URL_MAP[value.charCodeAt(inIdx + 1)];\n const c = BASE64_URL_MAP[value.charCodeAt(inIdx + 2)];\n const d = BASE64_URL_MAP[value.charCodeAt(inIdx + 3)];\n if (a < 0 || b < 0 || c < 0 || d < 0) {\n throw new Error('Invalid address encoding');\n }\n const triple = (a << 18) | (b << 12) | (c << 6) | d;\n const byte1 = (triple >> 16) & 0xff;\n const byte2 = (triple >> 8) & 0xff;\n const incomingChecksum = triple & 0xff;\n\n checksum += byte1;\n checksum += byte2;\n output[outIdx++] = byte1;\n output[outIdx++] = byte2;\n\n checksum &= 0xff;\n if (checksum !== incomingChecksum) {\n throw new Error('Address checksum mismatch');\n }\n\n return output;\n}\n\nfunction maskForBits(bits: number): number {\n return bits === 0 ? 0 : (1 << bits) - 1;\n}\n","import { encodeAddress } from '@thru/helpers';\nimport type { ThruClient, TransactionResult } from './types';\n\nconst feePayerQueueSymbol = Symbol.for('thru.sharedFeePayerQueues');\n\nfunction getFeePayerQueues(): Map<string, Promise<void>> {\n const globalQueues = globalThis as typeof globalThis & {\n [feePayerQueueSymbol]?: Map<string, Promise<void>>;\n };\n\n if (!globalQueues[feePayerQueueSymbol]) {\n globalQueues[feePayerQueueSymbol] = new Map<string, Promise<void>>();\n }\n\n return globalQueues[feePayerQueueSymbol];\n}\n\nexport async function getStateProof(\n client: ThruClient,\n address: string,\n proofType: number = 1,\n targetSlot?: bigint\n): Promise<Uint8Array> {\n const proofRequest: {\n address: string;\n proofType: number;\n targetSlot?: bigint;\n } = {\n address,\n proofType,\n };\n\n if (targetSlot !== undefined) {\n proofRequest.targetSlot = targetSlot;\n }\n\n const proof = await client.proofs.generate(proofRequest);\n\n if (!proof.proof || proof.proof.length === 0) {\n throw new Error(`No state proof returned for ${address}`);\n }\n\n return proof.proof;\n}\n\nexport async function trackTransaction(\n client: ThruClient,\n signature: string,\n timeoutMs: number = 5000\n): Promise<TransactionResult> {\n let finalizedSeen = false;\n\n try {\n for await (const update of client.transactions.track(signature, { timeoutMs })) {\n if (update.executionResult) {\n const vmError =\n update.executionResult.vmError !== undefined && update.executionResult.vmError !== null\n ? BigInt(update.executionResult.vmError)\n : 0n;\n const userErrorCode = update.executionResult.userErrorCode;\n const executionError =\n update.executionResult.executionResult !== undefined &&\n update.executionResult.executionResult !== null\n ? BigInt(update.executionResult.executionResult)\n : 0n;\n const success = vmError === 0n && executionError === 0n && userErrorCode === 0n;\n\n return {\n signature,\n status: success ? 'finalized' : 'failed',\n errorCode: vmError !== 0n ? vmError : executionError !== 0n ? executionError : userErrorCode,\n };\n }\n\n if (update.statusCode === 3) {\n finalizedSeen = true;\n }\n }\n\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n } catch {\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n}\n\nexport function toThruAddress(bytes: Uint8Array): string {\n return encodeAddress(bytes);\n}\n\nexport async function withSerializedFeePayer<T>(\n feePayerPublicKey: Uint8Array,\n work: () => Promise<T>\n): Promise<T> {\n const queueKey = toThruAddress(feePayerPublicKey);\n const feePayerQueues = getFeePayerQueues();\n const previous = feePayerQueues.get(queueKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => current);\n feePayerQueues.set(queueKey, tail);\n\n await previous;\n\n try {\n return await work();\n } finally {\n release();\n if (feePayerQueues.get(queueKey) === tail) {\n feePayerQueues.delete(queueKey);\n }\n }\n}\n","import {\n bytesToBase64Url,\n createValidateChallenge,\n fetchWalletNonce,\n} from '@thru/passkey-manager';\nimport type { AccountContext } from '@thru/passkey-manager';\nimport type { PasskeyChallengeResult, ThruClient } from './types';\n\nexport async function createPasskeyChallenge(opts: {\n client: ThruClient;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n}): Promise<PasskeyChallengeResult> {\n const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);\n const challenge = await createValidateChallenge(\n nonce,\n opts.accountCtx.accountAddresses,\n opts.invokeIx\n );\n\n return {\n challenge: bytesToBase64Url(challenge),\n nonce: nonce.toString(),\n };\n}\n","import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n concatenateInstructions,\n encodeValidateInstruction,\n hexToBytes,\n} from '@thru/passkey-manager';\nimport type { AccountContext } from '@thru/passkey-manager';\nimport { trackTransaction, withSerializedFeePayer } from './utils';\nimport type {\n BuiltPasskeyTransaction,\n PasskeySignaturePayload,\n PasskeyTransactionHeaderOverrides,\n ThruClient,\n TransactionResult,\n} from './types';\n\n/**\n * Builds and signs a passkey-manager transaction without submitting it.\n *\n * Callers that override the transaction nonce are responsible for coordinating\n * fee-payer nonce allocation before calling this helper. Use\n * `submitPasskeyTransaction` for the serialized one-off submit path.\n */\nexport async function buildPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<BuiltPasskeyTransaction> {\n const validateIx = encodeValidateInstruction({\n walletAccountIdx: opts.accountCtx.walletAccountIdx,\n authIdx: 0,\n signatureR: hexToBytes(opts.signatureR),\n signatureS: hexToBytes(opts.signatureS),\n authenticatorData: Buffer.from(opts.authenticatorData, 'base64'),\n clientDataJSON: Buffer.from(opts.clientDataJSON, 'base64'),\n });\n\n const instructionData = concatenateInstructions([validateIx, opts.invokeIx]);\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData,\n accounts: {\n readWrite: opts.accountCtx.readWriteAddresses,\n readOnly: opts.accountCtx.readOnlyAddresses,\n },\n header: {\n fee: 0n,\n ...opts.header,\n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n return {\n transaction,\n rawTransaction: transaction.toWire(),\n };\n}\n\nexport async function submitPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<TransactionResult> {\n return withSerializedFeePayer(opts.adminPublicKey, async () => {\n const { rawTransaction } = await buildPasskeyTransaction(opts);\n const signature = await opts.client.transactions.send(rawTransaction);\n return trackTransaction(opts.client, signature);\n });\n}\n","import type { PasskeyContextResult } from './types';\nimport { createPasskeyChallenge } from './challenge';\nimport { submitPasskeyTransaction } from './submit';\nimport type {\n PasskeyChallengeSubmitPayload,\n ThruClient,\n TransactionResult,\n} from './types';\n\nexport function createPasskeyHandlers<P>(opts: {\n buildContext: (params: P) => Promise<PasskeyContextResult>;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n client: ThruClient;\n challengeTtlMs?: number;\n}) {\n const pendingContexts = new Map<\n string,\n { context: PasskeyContextResult; createdAt: number }\n >();\n const challengeTtlMs = opts.challengeTtlMs ?? 5 * 60_000;\n\n function createPendingContextKey(\n walletAddress: string,\n nonce: string,\n challenge: string\n ): string {\n return `${walletAddress}:${nonce}:${challenge}`;\n }\n\n function prunePendingContexts(now = Date.now()): void {\n for (const [nonce, entry] of pendingContexts.entries()) {\n if (now - entry.createdAt > challengeTtlMs) {\n pendingContexts.delete(nonce);\n }\n }\n }\n\n return {\n challenge: async (walletAddress: string, params: P) => {\n prunePendingContexts();\n\n const context = await opts.buildContext(params);\n const challenge = await createPasskeyChallenge({\n client: opts.client,\n walletAddress,\n accountCtx: context.accountCtx,\n invokeIx: context.invokeIx,\n });\n\n pendingContexts.set(\n createPendingContextKey(walletAddress, challenge.nonce, challenge.challenge),\n {\n context,\n createdAt: Date.now(),\n }\n );\n\n return challenge;\n },\n submit: async (\n walletAddress: string,\n params: P,\n payload: PasskeyChallengeSubmitPayload\n ): Promise<TransactionResult> => {\n void params;\n prunePendingContexts();\n\n const pendingKey = createPendingContextKey(\n walletAddress,\n payload.nonce,\n payload.challenge\n );\n const pending = pendingContexts.get(pendingKey);\n if (!pending) {\n throw new Error('Missing or expired challenge nonce');\n }\n\n pendingContexts.delete(pendingKey);\n const { nonce: _nonce, challenge: _challenge, ...signaturePayload } = payload;\n\n return submitPasskeyTransaction({\n client: opts.client,\n adminPublicKey: opts.adminPublicKey,\n adminPrivateKey: opts.adminPrivateKey,\n walletAddress,\n accountCtx: pending.context.accountCtx,\n invokeIx: pending.context.invokeIx,\n ...signaturePayload,\n });\n },\n };\n}\n"],"mappings":"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","names":["PASSKEY_MANAGER_PROGRAM_ADDRESS","hexToBytes","hexToBytes","PASSKEY_MANAGER_PROGRAM_ADDRESS"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/create-wallet.ts","../src/server/utils.ts","../src/server/challenge.ts","../src/server/submit.ts","../src/server/handlers.ts"],"sourcesContent":["import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n base64UrlToBytes,\n buildAccountContext,\n createCredentialLookupSeed,\n createWalletSeed,\n deriveCredentialLookupAddress,\n deriveWalletAddress,\n encodeCreateInstruction,\n encodeRegisterCredentialInstruction,\n} from '@thru/programs/passkey-manager';\nimport {\n toThruAddress,\n getStateProof,\n trackTransaction,\n withSerializedFeePayer,\n} from \"./utils\";\nimport type { ThruClient } from \"./types\";\n\nexport async function createPasskeyWallet(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n adminAddress: string;\n pubkeyX: Uint8Array;\n pubkeyY: Uint8Array;\n credentialId?: string;\n walletName?: string;\n}): Promise<{ walletAddress: string; credentialLookupAddress?: string }> {\n const walletName = opts.walletName ?? \"default\";\n const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);\n const walletBytes = await deriveWalletAddress(\n seed,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const walletAddress = toThruAddress(walletBytes);\n\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let walletExists = false;\n try {\n await opts.client.accounts.get(walletAddress);\n walletExists = true;\n } catch {\n walletExists = false;\n }\n\n if (walletExists) return;\n\n const stateProof = await getStateProof(opts.client, walletAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const createIx = encodeCreateInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n authority: {\n tag: 1,\n pubkeyX: opts.pubkeyX,\n pubkeyY: opts.pubkeyY,\n },\n seed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: createIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(transaction.toWire());\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Wallet creation failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n\n let credentialLookupAddress: string | undefined;\n if (opts.credentialId) {\n const credentialIdBytes = base64UrlToBytes(opts.credentialId);\n const lookupAddressBytes = await deriveCredentialLookupAddress(\n credentialIdBytes,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const lookupAddress = toThruAddress(lookupAddressBytes);\n\n credentialLookupAddress = lookupAddress;\n\n try {\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let lookupExists = false;\n try {\n await opts.client.accounts.get(lookupAddress);\n lookupExists = true;\n } catch {\n lookupExists = false;\n }\n\n if (lookupExists) return;\n\n const credSeed = await createCredentialLookupSeed(credentialIdBytes);\n const stateProof = await getStateProof(opts.client, lookupAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [lookupAddressBytes],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const registerIx = encodeRegisterCredentialInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n lookupAccountIdx: accountCtx.getAccountIndex(lookupAddressBytes),\n seed: credSeed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: registerIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(\n transaction.toWire(),\n );\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Credential registration failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n } catch (error) {\n console.warn(\"Credential registration failed (non-fatal):\", error);\n }\n }\n\n return {\n walletAddress,\n credentialLookupAddress,\n };\n}\n","import { encodeAddress } from '@thru/sdk/helpers';\nimport type { ThruClient, TransactionResult } from './types';\n\nconst feePayerQueueSymbol = Symbol.for('thru.sharedFeePayerQueues');\n\nfunction getFeePayerQueues(): Map<string, Promise<void>> {\n const globalQueues = globalThis as typeof globalThis & {\n [feePayerQueueSymbol]?: Map<string, Promise<void>>;\n };\n\n if (!globalQueues[feePayerQueueSymbol]) {\n globalQueues[feePayerQueueSymbol] = new Map<string, Promise<void>>();\n }\n\n return globalQueues[feePayerQueueSymbol];\n}\n\nexport async function getStateProof(\n client: ThruClient,\n address: string,\n proofType: number = 1,\n targetSlot?: bigint\n): Promise<Uint8Array> {\n const proofRequest: {\n address: string;\n proofType: number;\n targetSlot?: bigint;\n } = {\n address,\n proofType,\n };\n\n if (targetSlot !== undefined) {\n proofRequest.targetSlot = targetSlot;\n }\n\n const proof = await client.proofs.generate(proofRequest);\n\n if (!proof.proof || proof.proof.length === 0) {\n throw new Error(`No state proof returned for ${address}`);\n }\n\n return proof.proof;\n}\n\nexport async function trackTransaction(\n client: ThruClient,\n signature: string,\n timeoutMs: number = 5000\n): Promise<TransactionResult> {\n let finalizedSeen = false;\n\n try {\n for await (const update of client.transactions.track(signature, { timeoutMs })) {\n if (update.executionResult) {\n const vmError =\n update.executionResult.vmError !== undefined && update.executionResult.vmError !== null\n ? BigInt(update.executionResult.vmError)\n : 0n;\n const userErrorCode = update.executionResult.userErrorCode;\n const executionError =\n update.executionResult.executionResult !== undefined &&\n update.executionResult.executionResult !== null\n ? BigInt(update.executionResult.executionResult)\n : 0n;\n const success = vmError === 0n && executionError === 0n && userErrorCode === 0n;\n\n return {\n signature,\n status: success ? 'finalized' : 'failed',\n errorCode: vmError !== 0n ? vmError : executionError !== 0n ? executionError : userErrorCode,\n };\n }\n\n if (update.statusCode === 3) {\n finalizedSeen = true;\n }\n }\n\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n } catch {\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n}\n\nexport function toThruAddress(bytes: Uint8Array): string {\n return encodeAddress(bytes);\n}\n\nexport async function withSerializedFeePayer<T>(\n feePayerPublicKey: Uint8Array,\n work: () => Promise<T>\n): Promise<T> {\n const queueKey = toThruAddress(feePayerPublicKey);\n const feePayerQueues = getFeePayerQueues();\n const previous = feePayerQueues.get(queueKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => current);\n feePayerQueues.set(queueKey, tail);\n\n await previous;\n\n try {\n return await work();\n } finally {\n release();\n if (feePayerQueues.get(queueKey) === tail) {\n feePayerQueues.delete(queueKey);\n }\n }\n}\n","import {\n bytesToBase64Url,\n createValidateChallenge,\n fetchWalletNonce,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport type { PasskeyChallengeResult, ThruClient } from './types';\n\nexport async function createPasskeyChallenge(opts: {\n client: ThruClient;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n}): Promise<PasskeyChallengeResult> {\n const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);\n const challenge = await createValidateChallenge(\n nonce,\n opts.accountCtx.accountAddresses,\n opts.invokeIx\n );\n\n return {\n challenge: bytesToBase64Url(challenge),\n nonce: nonce.toString(),\n };\n}\n","import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n concatenateInstructions,\n encodeValidateInstruction,\n hexToBytes,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport { trackTransaction, withSerializedFeePayer } from './utils';\nimport type {\n BuiltPasskeyTransaction,\n PasskeySignaturePayload,\n PasskeyTransactionHeaderOverrides,\n ThruClient,\n TransactionResult,\n} from './types';\n\nfunction base64ToBytes(base64: string): Uint8Array {\n type BufferLike = {\n from(value: string, encoding: 'base64'): Uint8Array;\n };\n const globalBuffer = (globalThis as { Buffer?: BufferLike }).Buffer;\n if (globalBuffer) {\n return globalBuffer.from(base64, 'base64');\n }\n\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Base64 decoding is not supported in this environment');\n}\n\n/**\n * Builds and signs a passkey-manager transaction without submitting it.\n *\n * Callers that override the transaction nonce are responsible for coordinating\n * fee-payer nonce allocation before calling this helper. Use\n * `submitPasskeyTransaction` for the serialized one-off submit path.\n */\nexport async function buildPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<BuiltPasskeyTransaction> {\n const validateIx = encodeValidateInstruction({\n walletAccountIdx: opts.accountCtx.walletAccountIdx,\n authIdx: 0,\n signatureR: hexToBytes(opts.signatureR),\n signatureS: hexToBytes(opts.signatureS),\n authenticatorData: base64ToBytes(opts.authenticatorData),\n clientDataJSON: base64ToBytes(opts.clientDataJSON),\n });\n\n const instructionData = concatenateInstructions([validateIx, opts.invokeIx]);\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData,\n accounts: {\n readWrite: opts.accountCtx.readWriteAddresses,\n readOnly: opts.accountCtx.readOnlyAddresses,\n },\n header: {\n fee: 0n,\n ...opts.header,\n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n return {\n transaction,\n rawTransaction: transaction.toWire(),\n };\n}\n\nexport async function submitPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<TransactionResult> {\n return withSerializedFeePayer(opts.adminPublicKey, async () => {\n const { rawTransaction } = await buildPasskeyTransaction(opts);\n const signature = await opts.client.transactions.send(rawTransaction);\n return trackTransaction(opts.client, signature);\n });\n}\n","import type { PasskeyContextResult } from './types';\nimport { createPasskeyChallenge } from './challenge';\nimport { submitPasskeyTransaction } from './submit';\nimport type {\n PasskeyChallengeSubmitPayload,\n ThruClient,\n TransactionResult,\n} from './types';\n\nexport function createPasskeyHandlers<P>(opts: {\n buildContext: (params: P) => Promise<PasskeyContextResult>;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n client: ThruClient;\n challengeTtlMs?: number;\n}) {\n const pendingContexts = new Map<\n string,\n { context: PasskeyContextResult; createdAt: number }\n >();\n const challengeTtlMs = opts.challengeTtlMs ?? 5 * 60_000;\n\n function createPendingContextKey(\n walletAddress: string,\n nonce: string,\n challenge: string\n ): string {\n return `${walletAddress}:${nonce}:${challenge}`;\n }\n\n function prunePendingContexts(now = Date.now()): void {\n for (const [nonce, entry] of pendingContexts.entries()) {\n if (now - entry.createdAt > challengeTtlMs) {\n pendingContexts.delete(nonce);\n }\n }\n }\n\n return {\n challenge: async (walletAddress: string, params: P) => {\n prunePendingContexts();\n\n const context = await opts.buildContext(params);\n const challenge = await createPasskeyChallenge({\n client: opts.client,\n walletAddress,\n accountCtx: context.accountCtx,\n invokeIx: context.invokeIx,\n });\n\n pendingContexts.set(\n createPendingContextKey(walletAddress, challenge.nonce, challenge.challenge),\n {\n context,\n createdAt: Date.now(),\n }\n );\n\n return challenge;\n },\n submit: async (\n walletAddress: string,\n params: P,\n payload: PasskeyChallengeSubmitPayload\n ): Promise<TransactionResult> => {\n void params;\n prunePendingContexts();\n\n const pendingKey = createPendingContextKey(\n walletAddress,\n payload.nonce,\n payload.challenge\n );\n const pending = pendingContexts.get(pendingKey);\n if (!pending) {\n throw new Error('Missing or expired challenge nonce');\n }\n\n pendingContexts.delete(pendingKey);\n const { nonce: _nonce, challenge: _challenge, ...signaturePayload } = payload;\n\n return submitPasskeyTransaction({\n client: opts.client,\n adminPublicKey: opts.adminPublicKey,\n adminPrivateKey: opts.adminPrivateKey,\n walletAddress,\n accountCtx: pending.context.accountCtx,\n invokeIx: pending.context.invokeIx,\n ...signaturePayload,\n });\n },\n };\n}\n"],"mappings":"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","names":["PASSKEY_MANAGER_PROGRAM_ADDRESS","PASSKEY_MANAGER_PROGRAM_ADDRESS"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PasskeySigningResult, PasskeyMetadata } from '@thru/passkey-manager';
|
|
1
|
+
import { PasskeySigningResult, PasskeyMetadata } from '@thru/programs/passkey-manager';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Signing result with stored passkey metadata attached.
|
|
@@ -33,6 +33,23 @@ interface PasskeyPopupContext {
|
|
|
33
33
|
origin?: string;
|
|
34
34
|
imageUrl?: string;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for stored passkey signing in embedded contexts.
|
|
38
|
+
*/
|
|
39
|
+
interface PasskeyStoredSigningOptions {
|
|
40
|
+
allowPopupFallback?: boolean;
|
|
41
|
+
/** Prefer an RP-scoped discoverable credential prompt over a stored
|
|
42
|
+
* credential-id lookup. Native WebViews can show misleading
|
|
43
|
+
* app-level "no passkey" UI when allowCredentials is stale, while a
|
|
44
|
+
* discoverable prompt correctly lets the wallet/RP choose the passkey. */
|
|
45
|
+
preferDiscoverable?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Options for passkey registration in embedded contexts.
|
|
49
|
+
*/
|
|
50
|
+
interface PasskeyRegistrationOptions {
|
|
51
|
+
allowPopupFallback?: boolean;
|
|
52
|
+
}
|
|
36
53
|
/**
|
|
37
54
|
* Account info passed through popup bridge.
|
|
38
55
|
*/
|
|
@@ -73,6 +90,7 @@ interface PasskeyPopupSigningResult {
|
|
|
73
90
|
clientDataJSONBase64Url: string;
|
|
74
91
|
signatureRBase64Url: string;
|
|
75
92
|
signatureSBase64Url: string;
|
|
93
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
76
94
|
}
|
|
77
95
|
interface PasskeyPopupStoredPasskey {
|
|
78
96
|
credentialId: string;
|
|
@@ -80,6 +98,10 @@ interface PasskeyPopupStoredPasskey {
|
|
|
80
98
|
publicKeyY: string;
|
|
81
99
|
rpId: string;
|
|
82
100
|
label?: string;
|
|
101
|
+
deviceName?: string;
|
|
102
|
+
devicePlatform?: string;
|
|
103
|
+
browserName?: string;
|
|
104
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
83
105
|
createdAt: string;
|
|
84
106
|
lastUsedAt: string;
|
|
85
107
|
}
|
|
@@ -92,6 +114,7 @@ interface PasskeyPopupRegistrationResult {
|
|
|
92
114
|
publicKeyX: string;
|
|
93
115
|
publicKeyY: string;
|
|
94
116
|
rpId: string;
|
|
117
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
95
118
|
}
|
|
96
119
|
type PasskeyPopupResponse = {
|
|
97
120
|
type: string;
|
|
@@ -122,4 +145,4 @@ type PasskeyPopupResponse = {
|
|
|
122
145
|
};
|
|
123
146
|
};
|
|
124
147
|
|
|
125
|
-
export type {
|
|
148
|
+
export type { PasskeyClientCapabilities as P, PasskeyPopupAccount as a, PasskeyPopupAction as b, PasskeyPopupContext as c, PasskeyPopupCreateRequestPayload as d, PasskeyPopupGetRequestPayload as e, PasskeyPopupGetStoredRequestPayload as f, PasskeyPopupRegistrationResult as g, PasskeyPopupRequest as h, PasskeyPopupRequestPayload as i, PasskeyPopupResponse as j, PasskeyPopupSigningResult as k, PasskeyPopupStoredPasskey as l, PasskeyPopupStoredSigningResult as m, PasskeyRegistrationOptions as n, PasskeyStoredSigningOptions as o, PasskeyStoredSigningResult as p };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PasskeySigningResult, PasskeyMetadata } from '@thru/passkey-manager';
|
|
1
|
+
import { PasskeySigningResult, PasskeyMetadata } from '@thru/programs/passkey-manager';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Signing result with stored passkey metadata attached.
|
|
@@ -33,6 +33,23 @@ interface PasskeyPopupContext {
|
|
|
33
33
|
origin?: string;
|
|
34
34
|
imageUrl?: string;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for stored passkey signing in embedded contexts.
|
|
38
|
+
*/
|
|
39
|
+
interface PasskeyStoredSigningOptions {
|
|
40
|
+
allowPopupFallback?: boolean;
|
|
41
|
+
/** Prefer an RP-scoped discoverable credential prompt over a stored
|
|
42
|
+
* credential-id lookup. Native WebViews can show misleading
|
|
43
|
+
* app-level "no passkey" UI when allowCredentials is stale, while a
|
|
44
|
+
* discoverable prompt correctly lets the wallet/RP choose the passkey. */
|
|
45
|
+
preferDiscoverable?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Options for passkey registration in embedded contexts.
|
|
49
|
+
*/
|
|
50
|
+
interface PasskeyRegistrationOptions {
|
|
51
|
+
allowPopupFallback?: boolean;
|
|
52
|
+
}
|
|
36
53
|
/**
|
|
37
54
|
* Account info passed through popup bridge.
|
|
38
55
|
*/
|
|
@@ -73,6 +90,7 @@ interface PasskeyPopupSigningResult {
|
|
|
73
90
|
clientDataJSONBase64Url: string;
|
|
74
91
|
signatureRBase64Url: string;
|
|
75
92
|
signatureSBase64Url: string;
|
|
93
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
76
94
|
}
|
|
77
95
|
interface PasskeyPopupStoredPasskey {
|
|
78
96
|
credentialId: string;
|
|
@@ -80,6 +98,10 @@ interface PasskeyPopupStoredPasskey {
|
|
|
80
98
|
publicKeyY: string;
|
|
81
99
|
rpId: string;
|
|
82
100
|
label?: string;
|
|
101
|
+
deviceName?: string;
|
|
102
|
+
devicePlatform?: string;
|
|
103
|
+
browserName?: string;
|
|
104
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
83
105
|
createdAt: string;
|
|
84
106
|
lastUsedAt: string;
|
|
85
107
|
}
|
|
@@ -92,6 +114,7 @@ interface PasskeyPopupRegistrationResult {
|
|
|
92
114
|
publicKeyX: string;
|
|
93
115
|
publicKeyY: string;
|
|
94
116
|
rpId: string;
|
|
117
|
+
authenticatorAttachment?: 'platform' | 'cross-platform' | null;
|
|
95
118
|
}
|
|
96
119
|
type PasskeyPopupResponse = {
|
|
97
120
|
type: string;
|
|
@@ -122,4 +145,4 @@ type PasskeyPopupResponse = {
|
|
|
122
145
|
};
|
|
123
146
|
};
|
|
124
147
|
|
|
125
|
-
export type {
|
|
148
|
+
export type { PasskeyClientCapabilities as P, PasskeyPopupAccount as a, PasskeyPopupAction as b, PasskeyPopupContext as c, PasskeyPopupCreateRequestPayload as d, PasskeyPopupGetRequestPayload as e, PasskeyPopupGetStoredRequestPayload as f, PasskeyPopupRegistrationResult as g, PasskeyPopupRequest as h, PasskeyPopupRequestPayload as i, PasskeyPopupResponse as j, PasskeyPopupSigningResult as k, PasskeyPopupStoredPasskey as l, PasskeyPopupStoredSigningResult as m, PasskeyRegistrationOptions as n, PasskeyStoredSigningOptions as o, PasskeyStoredSigningResult as p };
|