@zauthx402/sdk 0.1.5 → 0.1.7

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.
@@ -1,2 +1,2 @@
1
- export { d as ZauthMiddlewareOptions, b as createZauthMiddleware, z as zauthProvider } from '../index-CzB2rK59.mjs';
1
+ export { d as ZauthMiddlewareOptions, b as createZauthMiddleware, z as zauthProvider } from '../index-C2FGNEe1.mjs';
2
2
  import 'express';
@@ -1,2 +1,2 @@
1
- export { d as ZauthMiddlewareOptions, b as createZauthMiddleware, z as zauthProvider } from '../index-CzB2rK59.js';
1
+ export { d as ZauthMiddlewareOptions, b as createZauthMiddleware, z as zauthProvider } from '../index-C2FGNEe1.js';
2
2
  import 'express';
@@ -60,9 +60,9 @@ var require_constants = __commonJS({
60
60
  }
61
61
  });
62
62
 
63
- // ../../node_modules/node-gyp-build/node-gyp-build.js
63
+ // node_modules/node-gyp-build/node-gyp-build.js
64
64
  var require_node_gyp_build = __commonJS({
65
- "../../node_modules/node-gyp-build/node-gyp-build.js"(exports$1, module) {
65
+ "node_modules/node-gyp-build/node-gyp-build.js"(exports$1, module) {
66
66
  var fs = __require("fs");
67
67
  var path = __require("path");
68
68
  var os = __require("os");
@@ -229,9 +229,9 @@ var require_node_gyp_build = __commonJS({
229
229
  }
230
230
  });
231
231
 
232
- // ../../node_modules/node-gyp-build/index.js
232
+ // node_modules/node-gyp-build/index.js
233
233
  var require_node_gyp_build2 = __commonJS({
234
- "../../node_modules/node-gyp-build/index.js"(exports$1, module) {
234
+ "node_modules/node-gyp-build/index.js"(exports$1, module) {
235
235
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
236
236
  if (typeof runtimeRequire.addon === "function") {
237
237
  module.exports = runtimeRequire.addon.bind(runtimeRequire);
@@ -241,9 +241,9 @@ var require_node_gyp_build2 = __commonJS({
241
241
  }
242
242
  });
243
243
 
244
- // ../../node_modules/bufferutil/fallback.js
244
+ // node_modules/bufferutil/fallback.js
245
245
  var require_fallback = __commonJS({
246
- "../../node_modules/bufferutil/fallback.js"(exports$1, module) {
246
+ "node_modules/bufferutil/fallback.js"(exports$1, module) {
247
247
  var mask = (source, mask2, output, offset, length) => {
248
248
  for (var i = 0; i < length; i++) {
249
249
  output[offset + i] = source[i] ^ mask2[i & 3];
@@ -259,9 +259,9 @@ var require_fallback = __commonJS({
259
259
  }
260
260
  });
261
261
 
262
- // ../../node_modules/bufferutil/index.js
262
+ // node_modules/bufferutil/index.js
263
263
  var require_bufferutil = __commonJS({
264
- "../../node_modules/bufferutil/index.js"(exports$1, module) {
264
+ "node_modules/bufferutil/index.js"(exports$1, module) {
265
265
  try {
266
266
  module.exports = require_node_gyp_build2()(__dirname);
267
267
  } catch (e) {
@@ -775,9 +775,9 @@ var require_permessage_deflate = __commonJS({
775
775
  }
776
776
  });
777
777
 
778
- // ../../node_modules/utf-8-validate/fallback.js
778
+ // node_modules/utf-8-validate/fallback.js
779
779
  var require_fallback2 = __commonJS({
780
- "../../node_modules/utf-8-validate/fallback.js"(exports$1, module) {
780
+ "node_modules/utf-8-validate/fallback.js"(exports$1, module) {
781
781
  function isValidUTF8(buf) {
782
782
  const len = buf.length;
783
783
  let i = 0;
@@ -811,9 +811,9 @@ var require_fallback2 = __commonJS({
811
811
  }
812
812
  });
813
813
 
814
- // ../../node_modules/utf-8-validate/index.js
814
+ // node_modules/utf-8-validate/index.js
815
815
  var require_utf_8_validate = __commonJS({
816
- "../../node_modules/utf-8-validate/index.js"(exports$1, module) {
816
+ "node_modules/utf-8-validate/index.js"(exports$1, module) {
817
817
  try {
818
818
  module.exports = require_node_gyp_build2()(__dirname);
819
819
  } catch (e) {
@@ -3933,6 +3933,7 @@ var DEFAULT_CONFIG = {
3933
3933
  refund: {
3934
3934
  enabled: false,
3935
3935
  privateKey: process.env.ZAUTH_REFUND_PRIVATE_KEY,
3936
+ solanaPrivateKey: process.env.ZAUTH_SOLANA_PRIVATE_KEY,
3936
3937
  network: "base",
3937
3938
  triggers: {
3938
3939
  serverError: true,
@@ -3963,6 +3964,7 @@ function resolveConfig(config) {
3963
3964
  enabled: config.refund?.enabled ?? DEFAULT_CONFIG.refund.enabled,
3964
3965
  signer: config.refund?.signer,
3965
3966
  privateKey: config.refund?.privateKey ?? DEFAULT_CONFIG.refund.privateKey,
3967
+ solanaPrivateKey: config.refund?.solanaPrivateKey ?? DEFAULT_CONFIG.refund.solanaPrivateKey,
3966
3968
  network: config.refund?.network ?? DEFAULT_CONFIG.refund.network,
3967
3969
  triggers: {
3968
3970
  ...DEFAULT_CONFIG.refund.triggers,
@@ -4535,17 +4537,68 @@ function decodePaymentHeader(paymentHeader) {
4535
4537
  decoded = paymentHeader;
4536
4538
  }
4537
4539
  const parsed = JSON.parse(decoded);
4538
- const payer = parsed.payload?.authorization?.from || // x402 V2
4540
+ let payer = parsed.payload?.authorization?.from || // x402 V2 EVM
4539
4541
  parsed.payer || parsed.from || parsed.payload?.from || parsed.x?.signature?.address || null;
4542
+ if (!payer && parsed.payload?.transaction) {
4543
+ payer = extractSolanaFeePayer(parsed.payload.transaction);
4544
+ }
4540
4545
  const amount = parsed.payload?.authorization?.value || // x402 V2
4541
4546
  parsed.amount || parsed.payload?.amount || null;
4542
- const network = parsed.payload?.authorization?.network || // x402 V2
4547
+ let network = parsed.payload?.authorization?.network || // x402 V2 EVM
4543
4548
  parsed.network || parsed.payload?.network || null;
4549
+ if (!network && parsed.payload?.transaction && payer) {
4550
+ network = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
4551
+ }
4544
4552
  return { payer, amount, network };
4545
4553
  } catch {
4546
4554
  return null;
4547
4555
  }
4548
4556
  }
4557
+ function extractSolanaFeePayer(base64Transaction) {
4558
+ try {
4559
+ const txBytes = typeof Buffer !== "undefined" ? Buffer.from(base64Transaction, "base64") : Uint8Array.from(atob(base64Transaction), (c) => c.charCodeAt(0));
4560
+ let offset = 0;
4561
+ const numSignatures = txBytes[offset];
4562
+ offset += 1;
4563
+ offset += numSignatures * 64;
4564
+ const firstByte = txBytes[offset];
4565
+ if ((firstByte & 128) !== 0) {
4566
+ offset += 1;
4567
+ }
4568
+ offset += 3;
4569
+ const numAccounts = txBytes[offset];
4570
+ offset += 1;
4571
+ if (numAccounts > 0 && offset + 32 <= txBytes.length) {
4572
+ const feePayerBytes = txBytes.slice(offset, offset + 32);
4573
+ return base58Encode(feePayerBytes);
4574
+ }
4575
+ return null;
4576
+ } catch {
4577
+ return null;
4578
+ }
4579
+ }
4580
+ function base58Encode(bytes) {
4581
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
4582
+ const BASE = 58;
4583
+ let num = BigInt(0);
4584
+ for (const byte of bytes) {
4585
+ num = num * BigInt(256) + BigInt(byte);
4586
+ }
4587
+ let result = "";
4588
+ while (num > 0) {
4589
+ const remainder = Number(num % BigInt(BASE));
4590
+ num = num / BigInt(BASE);
4591
+ result = ALPHABET[remainder] + result;
4592
+ }
4593
+ for (const byte of bytes) {
4594
+ if (byte === 0) {
4595
+ result = "1" + result;
4596
+ } else {
4597
+ break;
4598
+ }
4599
+ }
4600
+ return result || "1";
4601
+ }
4549
4602
 
4550
4603
  // src/validator.ts
4551
4604
  function validateResponse(body, statusCode, config) {
@@ -4695,6 +4748,8 @@ var RefundExecutor = class {
4695
4748
  // YYYY-MM-DD
4696
4749
  lastCapResetMonth = (/* @__PURE__ */ new Date()).toISOString().slice(0, 7);
4697
4750
  // YYYY-MM
4751
+ // Track processed refundIds to prevent double execution within same session
4752
+ processedRefundIds = /* @__PURE__ */ new Set();
4698
4753
  constructor(client, config, debug = false) {
4699
4754
  this.client = client;
4700
4755
  this.config = config;
@@ -4787,6 +4842,11 @@ var RefundExecutor = class {
4787
4842
  case "rejection_ack":
4788
4843
  this.log("Refund rejection acknowledged", { refundId: msg.refundId });
4789
4844
  break;
4845
+ case "executing_ack":
4846
+ if (this.debug) {
4847
+ this.log("Refund executing acknowledged", { refundId: msg.refundId, status: msg.status });
4848
+ }
4849
+ break;
4790
4850
  case "pong":
4791
4851
  break;
4792
4852
  default:
@@ -4801,6 +4861,10 @@ var RefundExecutor = class {
4801
4861
  */
4802
4862
  async processSingleRefund(refund) {
4803
4863
  try {
4864
+ if (this.processedRefundIds.has(refund.id)) {
4865
+ this.log("Refund already processed in this session", { refundId: refund.id });
4866
+ return;
4867
+ }
4804
4868
  const endpointConfig = this.getEndpointConfig(refund.url);
4805
4869
  if (endpointConfig?.enabled === false) {
4806
4870
  this.log("Refunds disabled for endpoint", { url: refund.url });
@@ -4859,8 +4923,13 @@ var RefundExecutor = class {
4859
4923
  return;
4860
4924
  }
4861
4925
  }
4926
+ this.sendMessage({
4927
+ type: "refund_executing",
4928
+ refundId: refund.id
4929
+ });
4862
4930
  const result = await this.executeRefundTx(refund);
4863
4931
  if (result.success) {
4932
+ this.processedRefundIds.add(refund.id);
4864
4933
  this.sendMessage({
4865
4934
  type: "refund_confirmed",
4866
4935
  refundId: refund.id,
@@ -5059,14 +5128,98 @@ var RefundExecutor = class {
5059
5128
  }
5060
5129
  }
5061
5130
  /**
5062
- * Execute Solana refund
5131
+ * Execute Solana refund using @solana/kit v2 libraries
5063
5132
  */
5064
- async executeSolanaRefund(_refund, _amountRaw) {
5065
- return {
5066
- success: false,
5067
- error: "Solana refunds not yet implemented",
5068
- retryable: false
5069
- };
5133
+ async executeSolanaRefund(refund, amountRaw) {
5134
+ try {
5135
+ const solanaPrivateKey = this.config.solanaPrivateKey;
5136
+ if (!solanaPrivateKey) {
5137
+ return {
5138
+ success: false,
5139
+ error: "No Solana private key configured (set ZAUTH_SOLANA_PRIVATE_KEY)",
5140
+ retryable: false
5141
+ };
5142
+ }
5143
+ const { createKeyPairSignerFromPrivateKeyBytes } = await import('@solana/signers');
5144
+ const {
5145
+ createSolanaRpc,
5146
+ address,
5147
+ pipe,
5148
+ createTransactionMessage,
5149
+ setTransactionMessageFeePayer,
5150
+ setTransactionMessageLifetimeUsingBlockhash,
5151
+ appendTransactionMessageInstructions,
5152
+ signTransactionMessageWithSigners,
5153
+ getBase64EncodedWireTransaction
5154
+ } = await import('@solana/kit');
5155
+ const {
5156
+ findAssociatedTokenPda,
5157
+ getTransferInstruction,
5158
+ TOKEN_PROGRAM_ADDRESS
5159
+ } = await import('@solana-program/token');
5160
+ const bs58 = await import('bs58');
5161
+ const USDC_MINT = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
5162
+ const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
5163
+ const rpc = createSolanaRpc(rpcUrl);
5164
+ let signer;
5165
+ try {
5166
+ const secretKey = bs58.default.decode(solanaPrivateKey);
5167
+ const privateKeyBytes = secretKey.slice(0, 32);
5168
+ signer = await createKeyPairSignerFromPrivateKeyBytes(privateKeyBytes);
5169
+ } catch {
5170
+ return {
5171
+ success: false,
5172
+ error: "Invalid Solana private key format (expected base58)",
5173
+ retryable: false
5174
+ };
5175
+ }
5176
+ const recipientAddress = address(refund.recipientAddress);
5177
+ const [senderAta] = await findAssociatedTokenPda({
5178
+ mint: USDC_MINT,
5179
+ owner: signer.address,
5180
+ tokenProgram: TOKEN_PROGRAM_ADDRESS
5181
+ });
5182
+ const [recipientAta] = await findAssociatedTokenPda({
5183
+ mint: USDC_MINT,
5184
+ owner: recipientAddress,
5185
+ tokenProgram: TOKEN_PROGRAM_ADDRESS
5186
+ });
5187
+ const transferIx = getTransferInstruction({
5188
+ source: senderAta,
5189
+ destination: recipientAta,
5190
+ authority: signer,
5191
+ amount: BigInt(amountRaw)
5192
+ });
5193
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
5194
+ const tx = pipe(
5195
+ createTransactionMessage({ version: 0 }),
5196
+ (tx2) => setTransactionMessageFeePayer(signer.address, tx2),
5197
+ (tx2) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx2),
5198
+ (tx2) => appendTransactionMessageInstructions([transferIx], tx2)
5199
+ );
5200
+ const signedTx = await signTransactionMessageWithSigners(tx);
5201
+ const base64Tx = getBase64EncodedWireTransaction(signedTx);
5202
+ const txSignature = await rpc.sendTransaction(base64Tx, { encoding: "base64" }).send();
5203
+ this.log("Solana refund sent", {
5204
+ txHash: txSignature,
5205
+ to: refund.recipientAddress,
5206
+ amount: amountRaw
5207
+ });
5208
+ return {
5209
+ success: true,
5210
+ txHash: txSignature,
5211
+ amountRaw,
5212
+ gasCostCents: 0
5213
+ // Solana fees are negligible
5214
+ };
5215
+ } catch (error) {
5216
+ this.log("Solana refund failed", { error: error.message });
5217
+ return {
5218
+ success: false,
5219
+ error: error.message,
5220
+ retryable: true
5221
+ };
5222
+ }
5070
5223
  }
5071
5224
  /**
5072
5225
  * Get endpoint-specific config by matching URL patterns
@@ -5106,6 +5259,25 @@ function createZauthMiddleware(options) {
5106
5259
  if (config.debug) {
5107
5260
  console.log("[zauthSDK] Refund executor started");
5108
5261
  }
5262
+ client.updateRefundConfig({
5263
+ enabled: true,
5264
+ maxRefundUsdCents: Math.round((config.refund.maxRefundUsd || 1) * 100),
5265
+ dailyCapCents: config.refund.dailyCapUsd ? Math.round(config.refund.dailyCapUsd * 100) : void 0,
5266
+ monthlyCapCents: config.refund.monthlyCapUsd ? Math.round(config.refund.monthlyCapUsd * 100) : void 0,
5267
+ triggers: {
5268
+ serverError: config.refund.triggers?.serverError ?? true,
5269
+ timeout: config.refund.triggers?.timeout ?? true,
5270
+ emptyResponse: config.refund.triggers?.emptyResponse ?? true,
5271
+ schemaValidation: config.refund.triggers?.schemaValidation ?? false,
5272
+ minMeaningfulness: config.refund.triggers?.minMeaningfulness ?? 0.3
5273
+ }
5274
+ }).then((result) => {
5275
+ if (config.debug) {
5276
+ console.log("[zauthSDK] Refund config registered with server", { success: result.success });
5277
+ }
5278
+ }).catch((err) => {
5279
+ console.error("[zauthSDK] Failed to register refund config:", err.message);
5280
+ });
5109
5281
  }
5110
5282
  function shouldMonitorRoute(req) {
5111
5283
  if (options.shouldMonitor) {