better-near-auth 1.8.3 → 1.10.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 +83 -7
- package/dist/index.d.ts +16 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/auth-plugin/SKILL.md +171 -34
- package/skills/client/SKILL.md +1 -1
- package/skills/relay/SKILL.md +102 -12
- package/skills/siwn/SKILL.md +1 -1
- package/skills/subaccount/SKILL.md +4 -1
- package/skills/tanstack/SKILL.md +8 -6
package/README.md
CHANGED
|
@@ -44,15 +44,46 @@ npm install better-near-auth
|
|
|
44
44
|
siwn({
|
|
45
45
|
recipient: "myapp.com",
|
|
46
46
|
|
|
47
|
-
// Optional: enable gasless relay
|
|
48
|
-
relayer:
|
|
49
|
-
whitelistedContracts: ["myapp.near"],
|
|
50
|
-
},
|
|
47
|
+
// Optional: enable gasless relay (ephemeral mode by default)
|
|
48
|
+
relayer: true,
|
|
51
49
|
}),
|
|
52
50
|
],
|
|
53
51
|
});
|
|
54
52
|
```
|
|
55
53
|
|
|
54
|
+
**Relayer Configuration Options:**
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// Ephemeral mode (simplest) - auto-generated keypair
|
|
58
|
+
relayer: true
|
|
59
|
+
|
|
60
|
+
// Ephemeral mode (explicit) - same as above with custom settings
|
|
61
|
+
relayer: {
|
|
62
|
+
ephemeral: true,
|
|
63
|
+
whitelistedContracts: ["myapp.near"],
|
|
64
|
+
maxGasPerTransaction: "300000000000000",
|
|
65
|
+
maxDepositPerTransaction: "0",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Explicit mode - bring your own key
|
|
69
|
+
relayer: {
|
|
70
|
+
accountId: "relayer.myapp.near",
|
|
71
|
+
privateKey: process.env.RELAYER_PRIVATE_KEY,
|
|
72
|
+
whitelistedContracts: ["myapp.near"],
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Per-network configuration
|
|
76
|
+
relayer: {
|
|
77
|
+
mainnet: {
|
|
78
|
+
whitelistedContracts: ["myapp.near"],
|
|
79
|
+
},
|
|
80
|
+
testnet: {
|
|
81
|
+
whitelistedContracts: ["myapp.testnet"],
|
|
82
|
+
maxGasPerTransaction: "100000000000000", // lower for testing
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
56
87
|
3. Generate the schema to add the necessary fields and tables to the database.
|
|
57
88
|
|
|
58
89
|
```bash
|
|
@@ -183,15 +214,42 @@ await authClient.near.disconnect();
|
|
|
183
214
|
|
|
184
215
|
#### Relayer Configuration
|
|
185
216
|
|
|
217
|
+
The relayer can be configured in several ways:
|
|
218
|
+
|
|
219
|
+
| Value | Mode | Description |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `true` | Ephemeral | Auto-generated ED25519 keypair (default) |
|
|
222
|
+
| `RelayerEphemeralConfig` | Ephemeral | Ephemeral with custom settings |
|
|
223
|
+
| `RelayerExplicitConfig` | Explicit | Bring your own key |
|
|
224
|
+
| `RelayerDualNetworkConfig` | Mixed | Per-network configuration |
|
|
225
|
+
|
|
226
|
+
**Ephemeral Config (`RelayerEphemeralConfig`):**
|
|
227
|
+
|
|
228
|
+
| Option | Type | Default | Description |
|
|
229
|
+
|---|---|---|---|
|
|
230
|
+
| `whitelistedContracts` | `string[]` | — | Restrict relay to these contracts |
|
|
231
|
+
| `maxGasPerTransaction` | `string` | — | Max gas per relayed tx |
|
|
232
|
+
| `maxDepositPerTransaction` | `string` | — | Max deposit per relayed tx |
|
|
233
|
+
|
|
234
|
+
**Explicit Config (`RelayerExplicitConfig`):**
|
|
235
|
+
|
|
186
236
|
| Option | Type | Default | Description |
|
|
187
237
|
|---|---|---|---|
|
|
188
|
-
| `accountId` | `string` | — | Named relayer account (
|
|
189
|
-
| `privateKey` | `string` | — | Base64 private key (
|
|
238
|
+
| `accountId` | `string` | — | Named relayer account (required) |
|
|
239
|
+
| `privateKey` | `string` | — | Base64 private key (required) |
|
|
240
|
+
| `privateKeys` | `string[]` | — | Multiple keys for rotation |
|
|
190
241
|
| `whitelistedContracts` | `string[]` | — | Restrict relay to these contracts |
|
|
191
242
|
| `maxGasPerTransaction` | `string` | — | Max gas per relayed tx |
|
|
192
243
|
| `maxDepositPerTransaction` | `string` | — | Max deposit per relayed tx |
|
|
193
244
|
|
|
194
|
-
|
|
245
|
+
**Dual Network Config (`RelayerDualNetworkConfig`):**
|
|
246
|
+
|
|
247
|
+
| Option | Type | Default | Description |
|
|
248
|
+
|---|---|---|---|
|
|
249
|
+
| `mainnet` | `RelayerEphemeralConfig \| RelayerExplicitConfig` | — | Mainnet relayer config |
|
|
250
|
+
| `testnet` | `RelayerEphemeralConfig \| RelayerExplicitConfig` | — | Testnet relayer config |
|
|
251
|
+
|
|
252
|
+
When using `relayer: true` or ephemeral config (no `accountId`/`privateKey`), an ED25519 keypair is generated on first startup, the implicit account ID is derived from the public key, and the private key is encrypted with AES-256-GCM (using `BETTER_AUTH_SECRET` as KEK via HKDF-SHA256) and stored in the database. The same keypair is recovered on restart.
|
|
195
253
|
|
|
196
254
|
### Client Options
|
|
197
255
|
|
|
@@ -332,6 +390,10 @@ export const auth = betterAuth({
|
|
|
332
390
|
|
|
333
391
|
apiKey: process.env.FASTNEAR_API_KEY,
|
|
334
392
|
|
|
393
|
+
// Ephemeral mode (simplest)
|
|
394
|
+
relayer: true,
|
|
395
|
+
|
|
396
|
+
// OR explicit mode
|
|
335
397
|
relayer: {
|
|
336
398
|
accountId: "relayer.myapp.near",
|
|
337
399
|
privateKey: process.env.RELAYER_PRIVATE_KEY,
|
|
@@ -339,6 +401,17 @@ export const auth = betterAuth({
|
|
|
339
401
|
maxGasPerTransaction: "300000000000000",
|
|
340
402
|
maxDepositPerTransaction: "0",
|
|
341
403
|
},
|
|
404
|
+
|
|
405
|
+
// OR per-network configuration
|
|
406
|
+
relayer: {
|
|
407
|
+
mainnet: {
|
|
408
|
+
whitelistedContracts: ["myapp.near"],
|
|
409
|
+
},
|
|
410
|
+
testnet: {
|
|
411
|
+
whitelistedContracts: ["myapp.testnet"],
|
|
412
|
+
maxGasPerTransaction: "100000000000000",
|
|
413
|
+
},
|
|
414
|
+
},
|
|
342
415
|
}),
|
|
343
416
|
],
|
|
344
417
|
});
|
|
@@ -378,6 +451,9 @@ The plugin detects the network from the account ID:
|
|
|
378
451
|
| "Network ID mismatch" | Ensure networkId matches the account's network |
|
|
379
452
|
| Relay fails with "insufficient balance" | Fund the relayer account with NEAR |
|
|
380
453
|
| Relay fails with "contract not whitelisted" | Add `receiverId` to `whitelistedContracts` |
|
|
454
|
+
| Relayer not initializing (ephemeral mode) | Ensure `BETTER_AUTH_SECRET` is set; check startup logs for `[siwn] Relayer initialized` |
|
|
455
|
+
| Empty `relayer_key` table | Relayer config not being passed; use `relayer: true` or provide config object |
|
|
456
|
+
| "BETTER_AUTH_SECRET required" error | Required for ephemeral mode encryption; generate a secure random string |
|
|
381
457
|
|
|
382
458
|
## Examples
|
|
383
459
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,14 +2,27 @@ import type { DBAdapter } from "better-auth/types";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { type AccountId, type DualNetworkConfig, type ListAccountsResponseT, type ListedNearAccount, type Profile, type SubAccountConfig } from "./types.js";
|
|
4
4
|
export * from "./types.js";
|
|
5
|
-
|
|
6
|
-
accountId?:
|
|
7
|
-
privateKey?:
|
|
5
|
+
interface RelayerEphemeralConfig {
|
|
6
|
+
accountId?: never;
|
|
7
|
+
privateKey?: never;
|
|
8
|
+
ephemeral?: true;
|
|
9
|
+
whitelistedContracts?: string[];
|
|
10
|
+
maxGasPerTransaction?: string;
|
|
11
|
+
maxDepositPerTransaction?: string;
|
|
12
|
+
}
|
|
13
|
+
interface RelayerExplicitConfig {
|
|
14
|
+
accountId: string;
|
|
15
|
+
privateKey: string;
|
|
8
16
|
privateKeys?: string[];
|
|
9
17
|
whitelistedContracts?: string[];
|
|
10
18
|
maxGasPerTransaction?: string;
|
|
11
19
|
maxDepositPerTransaction?: string;
|
|
12
20
|
}
|
|
21
|
+
interface RelayerDualNetworkConfig {
|
|
22
|
+
mainnet?: RelayerEphemeralConfig | RelayerExplicitConfig;
|
|
23
|
+
testnet?: RelayerEphemeralConfig | RelayerExplicitConfig;
|
|
24
|
+
}
|
|
25
|
+
export type RelayerConfig = true | RelayerEphemeralConfig | RelayerExplicitConfig | RelayerDualNetworkConfig;
|
|
13
26
|
export interface SIWNPluginOptions {
|
|
14
27
|
recipient?: string;
|
|
15
28
|
recipients?: DualNetworkConfig<string>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,mBAAmB,CAAC;AASlE,OAAO,CAAC,MAAM,KAAK,CAAC;AAGpB,OAAO,EACN,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEtB,KAAK,OAAO,EAGZ,KAAK,gBAAgB,EAqBrB,MAAM,YAAY,CAAC;AACpB,cAAc,YAAY,CAAC;AA8D3B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -376,19 +376,29 @@ async function initRelayer(relayerConfig, network, adapter, secret, apiKey, rpcU
|
|
|
376
376
|
if (!relayerConfig) return null;
|
|
377
377
|
const headers = {};
|
|
378
378
|
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
let networkConfig;
|
|
380
|
+
if (relayerConfig === true) networkConfig = {};
|
|
381
|
+
else if ("mainnet" in relayerConfig || "testnet" in relayerConfig) {
|
|
382
|
+
const dualConfig = relayerConfig;
|
|
383
|
+
networkConfig = network === "mainnet" ? dualConfig.mainnet : dualConfig.testnet;
|
|
384
|
+
if (!networkConfig) return null;
|
|
385
|
+
} else networkConfig = relayerConfig;
|
|
386
|
+
if ("accountId" in networkConfig && networkConfig.accountId && (networkConfig.privateKey || networkConfig.privateKeys)) {
|
|
387
|
+
const keys = networkConfig.privateKeys ?? (networkConfig.privateKey ? [networkConfig.privateKey] : []);
|
|
381
388
|
let keyStore;
|
|
382
|
-
if (keys.length === 1) keyStore = new InMemoryKeyStore({ [
|
|
383
|
-
else keyStore = new RotatingKeyStore({ [
|
|
389
|
+
if (keys.length === 1) keyStore = new InMemoryKeyStore({ [networkConfig.accountId]: keys[0] });
|
|
390
|
+
else keyStore = new RotatingKeyStore({ [networkConfig.accountId]: keys });
|
|
384
391
|
const near = createNear(network, headers, rpcUrl, keyStore);
|
|
385
392
|
const explicitPublicKey = parseKey(keys[0]);
|
|
386
393
|
return {
|
|
387
394
|
near,
|
|
388
|
-
accountId:
|
|
395
|
+
accountId: networkConfig.accountId,
|
|
389
396
|
network,
|
|
390
397
|
mode: "explicit",
|
|
391
|
-
publicKey: explicitPublicKey.publicKey.toString()
|
|
398
|
+
publicKey: explicitPublicKey.publicKey.toString(),
|
|
399
|
+
whitelistedContracts: networkConfig.whitelistedContracts,
|
|
400
|
+
maxGasPerTransaction: networkConfig.maxGasPerTransaction,
|
|
401
|
+
maxDepositPerTransaction: networkConfig.maxDepositPerTransaction
|
|
392
402
|
};
|
|
393
403
|
}
|
|
394
404
|
const existing = await adapter.findOne({
|
|
@@ -413,6 +423,9 @@ async function initRelayer(relayerConfig, network, adapter, secret, apiKey, rpcU
|
|
|
413
423
|
network,
|
|
414
424
|
mode: "ephemeral",
|
|
415
425
|
publicKey: keyPair.publicKey.toString(),
|
|
426
|
+
whitelistedContracts: networkConfig.whitelistedContracts,
|
|
427
|
+
maxGasPerTransaction: networkConfig.maxGasPerTransaction,
|
|
428
|
+
maxDepositPerTransaction: networkConfig.maxDepositPerTransaction,
|
|
416
429
|
createdAt: existing.createdAt,
|
|
417
430
|
lastUsedAt: existing.lastUsedAt
|
|
418
431
|
};
|
|
@@ -447,6 +460,9 @@ async function initRelayer(relayerConfig, network, adapter, secret, apiKey, rpcU
|
|
|
447
460
|
network,
|
|
448
461
|
mode: "ephemeral",
|
|
449
462
|
publicKey: keyPair.publicKey.toString(),
|
|
463
|
+
whitelistedContracts: networkConfig.whitelistedContracts,
|
|
464
|
+
maxGasPerTransaction: networkConfig.maxGasPerTransaction,
|
|
465
|
+
maxDepositPerTransaction: networkConfig.maxDepositPerTransaction,
|
|
450
466
|
createdAt,
|
|
451
467
|
lastUsedAt: createdAt
|
|
452
468
|
};
|
|
@@ -494,7 +510,8 @@ const siwn = (options) => {
|
|
|
494
510
|
};
|
|
495
511
|
const getRelayerConfig = (network) => {
|
|
496
512
|
if (!options.relayer) return void 0;
|
|
497
|
-
if (
|
|
513
|
+
if (options.relayer === true) return true;
|
|
514
|
+
if ("mainnet" in options.relayer || "testnet" in options.relayer) return options.relayer[network];
|
|
498
515
|
return options.relayer;
|
|
499
516
|
};
|
|
500
517
|
const getRpcUrl = (network) => {
|
|
@@ -516,8 +533,12 @@ const siwn = (options) => {
|
|
|
516
533
|
const fromSecrets = getParentKey(network);
|
|
517
534
|
if (fromSecrets) return fromSecrets;
|
|
518
535
|
const relayerCfg = getRelayerConfig(network);
|
|
519
|
-
const
|
|
520
|
-
if (
|
|
536
|
+
const subAccountCfg = getSubAccountConfig(network);
|
|
537
|
+
if (!relayerCfg || relayerCfg === true) return void 0;
|
|
538
|
+
if ("mainnet" in relayerCfg || "testnet" in relayerCfg) return void 0;
|
|
539
|
+
const explicitCfg = relayerCfg;
|
|
540
|
+
const parent = subAccountCfg?.parentAccount ?? explicitCfg.accountId;
|
|
541
|
+
if (parent && parent === explicitCfg.accountId) return explicitCfg.privateKey ?? explicitCfg.privateKeys?.[0];
|
|
521
542
|
};
|
|
522
543
|
const primaryNetwork = getSupportedNetworks()[0];
|
|
523
544
|
const relayerStates = /* @__PURE__ */ new Map();
|
|
@@ -528,12 +549,21 @@ const siwn = (options) => {
|
|
|
528
549
|
if (relayerStates.has(network)) return relayerStates.get(network) ?? null;
|
|
529
550
|
const existingInit = relayerInitPromises.get(network);
|
|
530
551
|
if (existingInit) return existingInit;
|
|
531
|
-
const
|
|
552
|
+
const relayerCfg = getRelayerConfig(network);
|
|
553
|
+
const initPromise = initRelayer(relayerCfg, network, adapter, secret, apiKey, getRpcUrl(network)).then((state) => {
|
|
532
554
|
relayerStates.set(network, state);
|
|
533
555
|
relayerInitPromises.delete(network);
|
|
556
|
+
if (state) {
|
|
557
|
+
console.log(`[siwn] Relayer initialized: ${state.accountId} (${network}, ${state.mode})`);
|
|
558
|
+
if (state.mode === "ephemeral") {
|
|
559
|
+
console.log(`[siwn] Fund this account with NEAR to enable gasless relay`);
|
|
560
|
+
console.log(`[siwn] Private key is encrypted in DB — persists across restarts`);
|
|
561
|
+
}
|
|
562
|
+
} else if (relayerCfg) console.warn(`[siwn] Relayer config provided but not initialized for ${network}. Check BETTER_AUTH_SECRET for ephemeral mode.`);
|
|
534
563
|
return state;
|
|
535
564
|
}).catch((error) => {
|
|
536
565
|
relayerInitPromises.delete(network);
|
|
566
|
+
console.error(`[siwn] Failed to initialize relayer for ${network}:`, error);
|
|
537
567
|
throw error;
|
|
538
568
|
});
|
|
539
569
|
relayerInitPromises.set(network, initPromise);
|
|
@@ -1148,29 +1178,34 @@ const siwn = (options) => {
|
|
|
1148
1178
|
status: 401
|
|
1149
1179
|
});
|
|
1150
1180
|
const relayerConfigForNetwork = getRelayerConfig(network);
|
|
1151
|
-
|
|
1152
|
-
|
|
1181
|
+
const isDualNetwork = relayerConfigForNetwork && typeof relayerConfigForNetwork === "object" && ("mainnet" in relayerConfigForNetwork || "testnet" in relayerConfigForNetwork);
|
|
1182
|
+
const configWithLimits = relayerConfigForNetwork && typeof relayerConfigForNetwork === "object" && !isDualNetwork ? relayerConfigForNetwork : void 0;
|
|
1183
|
+
const whitelistedContracts = configWithLimits?.whitelistedContracts;
|
|
1184
|
+
if (whitelistedContracts?.length) {
|
|
1185
|
+
if (!whitelistedContracts.includes(delegateAction.receiverId)) throw new APIError("FORBIDDEN", {
|
|
1153
1186
|
message: `Contract ${delegateAction.receiverId} is not whitelisted for relay`,
|
|
1154
1187
|
status: 403
|
|
1155
1188
|
});
|
|
1156
1189
|
}
|
|
1157
|
-
|
|
1190
|
+
const maxGasPerTransaction = configWithLimits?.maxGasPerTransaction;
|
|
1191
|
+
if (maxGasPerTransaction) {
|
|
1158
1192
|
const totalGas = delegateAction.actions.reduce((sum, a) => {
|
|
1159
1193
|
return sum + ("functionCall" in a ? a.functionCall.gas : 0n);
|
|
1160
1194
|
}, 0n);
|
|
1161
|
-
if (totalGas > BigInt(
|
|
1162
|
-
message: `Transaction gas (${totalGas}) exceeds relayer limit (${
|
|
1195
|
+
if (totalGas > BigInt(maxGasPerTransaction)) throw new APIError("BAD_REQUEST", {
|
|
1196
|
+
message: `Transaction gas (${totalGas}) exceeds relayer limit (${maxGasPerTransaction})`,
|
|
1163
1197
|
status: 400
|
|
1164
1198
|
});
|
|
1165
1199
|
}
|
|
1166
|
-
|
|
1200
|
+
const maxDepositPerTransaction = configWithLimits?.maxDepositPerTransaction;
|
|
1201
|
+
if (maxDepositPerTransaction) {
|
|
1167
1202
|
const totalDeposit = delegateAction.actions.reduce((sum, a) => {
|
|
1168
1203
|
if ("functionCall" in a) return sum + a.functionCall.deposit;
|
|
1169
1204
|
if ("transfer" in a) return sum + a.transfer.deposit;
|
|
1170
1205
|
return sum;
|
|
1171
1206
|
}, 0n);
|
|
1172
|
-
if (totalDeposit > BigInt(
|
|
1173
|
-
message: `Transaction deposit (${totalDeposit}) exceeds relayer limit (${
|
|
1207
|
+
if (totalDeposit > BigInt(maxDepositPerTransaction)) throw new APIError("BAD_REQUEST", {
|
|
1208
|
+
message: `Transaction deposit (${totalDeposit}) exceeds relayer limit (${maxDepositPerTransaction})`,
|
|
1174
1209
|
status: 400
|
|
1175
1210
|
});
|
|
1176
1211
|
}
|