better-near-auth 1.8.3 → 1.9.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 CHANGED
@@ -44,15 +44,45 @@ 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 (default) - auto-generated keypair
58
+ relayer: true
59
+
60
+ // Ephemeral with custom settings
61
+ relayer: {
62
+ whitelistedContracts: ["myapp.near"],
63
+ maxGasPerTransaction: "300000000000000",
64
+ maxDepositPerTransaction: "0",
65
+ }
66
+
67
+ // Explicit mode - bring your own key
68
+ relayer: {
69
+ accountId: "relayer.myapp.near",
70
+ privateKey: process.env.RELAYER_PRIVATE_KEY,
71
+ whitelistedContracts: ["myapp.near"],
72
+ }
73
+
74
+ // Per-network configuration
75
+ relayer: {
76
+ mainnet: {
77
+ whitelistedContracts: ["myapp.near"],
78
+ },
79
+ testnet: {
80
+ whitelistedContracts: ["myapp.testnet"],
81
+ maxGasPerTransaction: "100000000000000", // lower for testing
82
+ },
83
+ }
84
+ ```
85
+
56
86
  3. Generate the schema to add the necessary fields and tables to the database.
57
87
 
58
88
  ```bash
@@ -183,15 +213,42 @@ await authClient.near.disconnect();
183
213
 
184
214
  #### Relayer Configuration
185
215
 
216
+ The relayer can be configured in several ways:
217
+
218
+ | Value | Mode | Description |
219
+ |---|---|---|
220
+ | `true` | Ephemeral | Auto-generated ED25519 keypair (default) |
221
+ | `RelayerEphemeralConfig` | Ephemeral | Ephemeral with custom settings |
222
+ | `RelayerExplicitConfig` | Explicit | Bring your own key |
223
+ | `RelayerDualNetworkConfig` | Mixed | Per-network configuration |
224
+
225
+ **Ephemeral Config (`RelayerEphemeralConfig`):**
226
+
227
+ | Option | Type | Default | Description |
228
+ |---|---|---|---|
229
+ | `whitelistedContracts` | `string[]` | — | Restrict relay to these contracts |
230
+ | `maxGasPerTransaction` | `string` | — | Max gas per relayed tx |
231
+ | `maxDepositPerTransaction` | `string` | — | Max deposit per relayed tx |
232
+
233
+ **Explicit Config (`RelayerExplicitConfig`):**
234
+
186
235
  | Option | Type | Default | Description |
187
236
  |---|---|---|---|
188
- | `accountId` | `string` | — | Named relayer account (explicit mode) |
189
- | `privateKey` | `string` | — | Base64 private key (explicit mode) |
237
+ | `accountId` | `string` | — | Named relayer account (required) |
238
+ | `privateKey` | `string` | — | Base64 private key (required) |
239
+ | `privateKeys` | `string[]` | — | Multiple keys for rotation |
190
240
  | `whitelistedContracts` | `string[]` | — | Restrict relay to these contracts |
191
241
  | `maxGasPerTransaction` | `string` | — | Max gas per relayed tx |
192
242
  | `maxDepositPerTransaction` | `string` | — | Max deposit per relayed tx |
193
243
 
194
- When `accountId` and `privateKey` are omitted, the relayer starts in **ephemeral mode**: 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.
244
+ **Dual Network Config (`RelayerDualNetworkConfig`):**
245
+
246
+ | Option | Type | Default | Description |
247
+ |---|---|---|---|
248
+ | `mainnet` | `RelayerEphemeralConfig \| RelayerExplicitConfig` | — | Mainnet relayer config |
249
+ | `testnet` | `RelayerEphemeralConfig \| RelayerExplicitConfig` | — | Testnet relayer config |
250
+
251
+ 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
252
 
196
253
  ### Client Options
197
254
 
@@ -332,6 +389,10 @@ export const auth = betterAuth({
332
389
 
333
390
  apiKey: process.env.FASTNEAR_API_KEY,
334
391
 
392
+ // Ephemeral mode (simplest)
393
+ relayer: true,
394
+
395
+ // OR explicit mode
335
396
  relayer: {
336
397
  accountId: "relayer.myapp.near",
337
398
  privateKey: process.env.RELAYER_PRIVATE_KEY,
@@ -339,6 +400,17 @@ export const auth = betterAuth({
339
400
  maxGasPerTransaction: "300000000000000",
340
401
  maxDepositPerTransaction: "0",
341
402
  },
403
+
404
+ // OR per-network configuration
405
+ relayer: {
406
+ mainnet: {
407
+ whitelistedContracts: ["myapp.near"],
408
+ },
409
+ testnet: {
410
+ whitelistedContracts: ["myapp.testnet"],
411
+ maxGasPerTransaction: "100000000000000",
412
+ },
413
+ },
342
414
  }),
343
415
  ],
344
416
  });
@@ -378,6 +450,9 @@ The plugin detects the network from the account ID:
378
450
  | "Network ID mismatch" | Ensure networkId matches the account's network |
379
451
  | Relay fails with "insufficient balance" | Fund the relayer account with NEAR |
380
452
  | Relay fails with "contract not whitelisted" | Add `receiverId` to `whitelistedContracts` |
453
+ | Relayer not initializing (ephemeral mode) | Ensure `BETTER_AUTH_SECRET` is set; check startup logs for `[siwn] Relayer initialized` |
454
+ | Empty `relayer_key` table | Relayer config not being passed; use `relayer: true` or provide config object |
455
+ | "BETTER_AUTH_SECRET required" error | Required for ephemeral mode encryption; generate a secure random string |
381
456
 
382
457
  ## Examples
383
458
 
package/dist/index.d.ts CHANGED
@@ -2,14 +2,26 @@ 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
- export interface RelayerConfig {
6
- accountId?: string;
7
- privateKey?: string;
5
+ interface RelayerEphemeralConfig {
6
+ accountId?: never;
7
+ privateKey?: never;
8
+ whitelistedContracts?: string[];
9
+ maxGasPerTransaction?: string;
10
+ maxDepositPerTransaction?: string;
11
+ }
12
+ interface RelayerExplicitConfig {
13
+ accountId: string;
14
+ privateKey: string;
8
15
  privateKeys?: string[];
9
16
  whitelistedContracts?: string[];
10
17
  maxGasPerTransaction?: string;
11
18
  maxDepositPerTransaction?: string;
12
19
  }
20
+ interface RelayerDualNetworkConfig {
21
+ mainnet?: RelayerEphemeralConfig | RelayerExplicitConfig;
22
+ testnet?: RelayerEphemeralConfig | RelayerExplicitConfig;
23
+ }
24
+ export type RelayerConfig = true | RelayerEphemeralConfig | RelayerExplicitConfig | RelayerDualNetworkConfig;
13
25
  export interface SIWNPluginOptions {
14
26
  recipient?: string;
15
27
  recipients?: DualNetworkConfig<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
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
- if (relayerConfig.accountId && (relayerConfig.privateKey || relayerConfig.privateKeys)) {
380
- const keys = relayerConfig.privateKeys ?? (relayerConfig.privateKey ? [relayerConfig.privateKey] : []);
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({ [relayerConfig.accountId]: keys[0] });
383
- else keyStore = new RotatingKeyStore({ [relayerConfig.accountId]: keys });
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: relayerConfig.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 ("mainnet" in options.relayer && typeof options.relayer.mainnet === "object") return options.relayer[network];
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 parent = getSubAccountConfig(network)?.parentAccount ?? relayerCfg?.accountId;
520
- if (parent && parent === relayerCfg?.accountId) return relayerCfg.privateKey ?? relayerCfg.privateKeys?.[0];
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 initPromise = initRelayer(getRelayerConfig(network), network, adapter, secret, apiKey, getRpcUrl(network)).then((state) => {
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
- if (relayerConfigForNetwork?.whitelistedContracts?.length) {
1152
- if (!relayerConfigForNetwork.whitelistedContracts.includes(delegateAction.receiverId)) throw new APIError("FORBIDDEN", {
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
- if (relayerConfigForNetwork?.maxGasPerTransaction) {
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(relayerConfigForNetwork.maxGasPerTransaction)) throw new APIError("BAD_REQUEST", {
1162
- message: `Transaction gas (${totalGas}) exceeds relayer limit (${relayerConfigForNetwork.maxGasPerTransaction})`,
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
- if (relayerConfigForNetwork?.maxDepositPerTransaction) {
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(relayerConfigForNetwork.maxDepositPerTransaction)) throw new APIError("BAD_REQUEST", {
1173
- message: `Transaction deposit (${totalDeposit}) exceeds relayer limit (${relayerConfigForNetwork.maxDepositPerTransaction})`,
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
  }