@solvapay/server 1.0.7 → 1.0.8-preview.10

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/index.cjs CHANGED
@@ -4317,6 +4317,7 @@ __export(index_exports, {
4317
4317
  activatePlanCore: () => activatePlanCore,
4318
4318
  buildAuthInfoFromBearer: () => buildAuthInfoFromBearer,
4319
4319
  cancelPurchaseCore: () => cancelPurchaseCore,
4320
+ checkPurchaseCore: () => checkPurchaseCore,
4320
4321
  createCheckoutSessionCore: () => createCheckoutSessionCore,
4321
4322
  createCustomerSessionCore: () => createCustomerSessionCore,
4322
4323
  createMcpOAuthBridge: () => createMcpOAuthBridge,
@@ -4331,8 +4332,10 @@ __export(index_exports, {
4331
4332
  getCustomerBalanceCore: () => getCustomerBalanceCore,
4332
4333
  getCustomerRefFromBearerAuthHeader: () => getCustomerRefFromBearerAuthHeader,
4333
4334
  getCustomerRefFromJwtPayload: () => getCustomerRefFromJwtPayload,
4335
+ getMerchantCore: () => getMerchantCore,
4334
4336
  getOAuthAuthorizationServerResponse: () => getOAuthAuthorizationServerResponse,
4335
4337
  getOAuthProtectedResourceResponse: () => getOAuthProtectedResourceResponse,
4338
+ getProductCore: () => getProductCore,
4336
4339
  handleRouteError: () => handleRouteError,
4337
4340
  isErrorResult: () => isErrorResult,
4338
4341
  jsonSchemaToZodRawShape: () => jsonSchemaToZodRawShape,
@@ -4342,12 +4345,13 @@ __export(index_exports, {
4342
4345
  reactivatePurchaseCore: () => reactivatePurchaseCore,
4343
4346
  registerVirtualToolsMcpImpl: () => registerVirtualToolsMcpImpl,
4344
4347
  syncCustomerCore: () => syncCustomerCore,
4348
+ trackUsageCore: () => trackUsageCore,
4345
4349
  verifyWebhook: () => verifyWebhook,
4346
4350
  withRetry: () => withRetry
4347
4351
  });
4348
4352
  module.exports = __toCommonJS(index_exports);
4349
4353
  var import_node_crypto = __toESM(require("crypto"), 1);
4350
- var import_core6 = require("@solvapay/core");
4354
+ var import_core8 = require("@solvapay/core");
4351
4355
 
4352
4356
  // src/client.ts
4353
4357
  var import_core = require("@solvapay/core");
@@ -4455,6 +4459,36 @@ function createSolvaPayClient(opts) {
4455
4459
  purchases: customer.purchases || []
4456
4460
  };
4457
4461
  },
4462
+ // GET: /v1/sdk/merchant
4463
+ async getMerchant() {
4464
+ const url = `${base}/v1/sdk/merchant`;
4465
+ const res = await fetch(url, {
4466
+ method: "GET",
4467
+ headers
4468
+ });
4469
+ if (!res.ok) {
4470
+ const error = await res.text();
4471
+ log(`\u274C API Error: ${res.status} - ${error}`);
4472
+ throw new import_core.SolvaPayError(`Get merchant failed (${res.status}): ${error}`);
4473
+ }
4474
+ return res.json();
4475
+ },
4476
+ // GET: /v1/sdk/products/{productRef}
4477
+ async getProduct(productRef) {
4478
+ const url = `${base}/v1/sdk/products/${encodeURIComponent(productRef)}`;
4479
+ const res = await fetch(url, {
4480
+ method: "GET",
4481
+ headers
4482
+ });
4483
+ if (!res.ok) {
4484
+ const error = await res.text();
4485
+ log(`\u274C API Error: ${res.status} - ${error}`);
4486
+ throw new import_core.SolvaPayError(`Get product failed (${res.status}): ${error}`);
4487
+ }
4488
+ const result = await res.json();
4489
+ const data = result.data || {};
4490
+ return { ...data, ...result };
4491
+ },
4458
4492
  // Product management methods (primarily for integration tests)
4459
4493
  // GET: /v1/sdk/products
4460
4494
  async listProducts() {
@@ -6060,7 +6094,8 @@ var McpBearerAuthError = class extends Error {
6060
6094
  function base64UrlDecode(input) {
6061
6095
  const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
6062
6096
  const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
6063
- return Buffer.from(padded, "base64").toString("utf8");
6097
+ const bytes = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
6098
+ return new TextDecoder().decode(bytes);
6064
6099
  }
6065
6100
  function extractBearerToken(authorization) {
6066
6101
  if (!authorization) return null;
@@ -6287,26 +6322,128 @@ function handleRouteError(error, operationName, defaultMessage) {
6287
6322
  }
6288
6323
 
6289
6324
  // src/helpers/auth.ts
6325
+ function base64UrlDecode2(input) {
6326
+ const padded = input.replace(/-/g, "+").replace(/_/g, "/");
6327
+ const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
6328
+ const base64 = padded + padding;
6329
+ if (typeof atob === "function") {
6330
+ const binary = atob(base64);
6331
+ let result = "";
6332
+ for (let i = 0; i < binary.length; i++) {
6333
+ result += String.fromCharCode(binary.charCodeAt(i));
6334
+ }
6335
+ try {
6336
+ return decodeURIComponent(escape(result));
6337
+ } catch {
6338
+ return result;
6339
+ }
6340
+ }
6341
+ const BufferCtor = globalThis.Buffer;
6342
+ if (BufferCtor) {
6343
+ return BufferCtor.from(base64, "base64").toString("utf-8");
6344
+ }
6345
+ throw new Error("No base64 decoder available in this runtime");
6346
+ }
6347
+ function decodeJwtUnverified(token) {
6348
+ const parts = token.split(".");
6349
+ if (parts.length !== 3) return null;
6350
+ try {
6351
+ const json = base64UrlDecode2(parts[1]);
6352
+ const payload = JSON.parse(json);
6353
+ if (typeof payload !== "object" || payload === null) return null;
6354
+ return payload;
6355
+ } catch {
6356
+ return null;
6357
+ }
6358
+ }
6359
+ function extractBearerToken2(request) {
6360
+ const authHeader = request.headers.get("authorization");
6361
+ if (!authHeader || !authHeader.toLowerCase().startsWith("bearer ")) return null;
6362
+ const token = authHeader.slice(7).trim();
6363
+ return token.length > 0 ? token : null;
6364
+ }
6365
+ function readEnv(name) {
6366
+ const proc = globalThis.process;
6367
+ return proc?.env?.[name];
6368
+ }
6369
+ function isStrictMode() {
6370
+ return readEnv("SOLVAPAY_AUTH_STRICT") === "true";
6371
+ }
6372
+ function getConfiguredSecret() {
6373
+ return readEnv("SOLVAPAY_JWT_SECRET") || readEnv("SUPABASE_JWT_SECRET");
6374
+ }
6375
+ async function verifyHs256(token, secret) {
6376
+ try {
6377
+ const { jwtVerify: jwtVerify2 } = await Promise.resolve().then(() => (init_webapi(), webapi_exports));
6378
+ const key = new TextEncoder().encode(secret);
6379
+ const { payload } = await jwtVerify2(token, key, { algorithms: ["HS256"] });
6380
+ return payload;
6381
+ } catch {
6382
+ return null;
6383
+ }
6384
+ }
6385
+ function pickName(payload) {
6386
+ const metadataFullName = typeof payload.user_metadata?.full_name === "string" ? payload.user_metadata.full_name : null;
6387
+ const metadataName = typeof payload.user_metadata?.name === "string" ? payload.user_metadata.name : null;
6388
+ const claimName = typeof payload.name === "string" ? payload.name : null;
6389
+ return metadataFullName || metadataName || claimName || null;
6390
+ }
6391
+ function pickEmail(payload) {
6392
+ return typeof payload.email === "string" ? payload.email : null;
6393
+ }
6394
+ function unauthorized(details) {
6395
+ return { error: "Unauthorized", status: 401, details };
6396
+ }
6290
6397
  async function getAuthenticatedUserCore(request, options = {}) {
6291
6398
  try {
6292
- const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
6293
- const userIdOrError = requireUserId(request);
6294
- if (userIdOrError instanceof Response) {
6295
- const clonedResponse = userIdOrError.clone();
6296
- const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
6297
- return {
6298
- error: body.error || "Unauthorized",
6299
- status: userIdOrError.status,
6300
- details: body.error || "Unauthorized"
6301
- };
6399
+ const includeEmail = options.includeEmail !== false;
6400
+ const includeName = options.includeName !== false;
6401
+ const headerUserId = request.headers.get("x-user-id");
6402
+ if (headerUserId) {
6403
+ let email = null;
6404
+ let name = null;
6405
+ if (includeEmail || includeName) {
6406
+ const token2 = extractBearerToken2(request);
6407
+ if (token2) {
6408
+ const secret2 = getConfiguredSecret();
6409
+ const payload2 = secret2 ? await verifyHs256(token2, secret2) : isStrictMode() ? null : decodeJwtUnverified(token2);
6410
+ if (payload2) {
6411
+ if (includeEmail) email = pickEmail(payload2);
6412
+ if (includeName) name = pickName(payload2);
6413
+ }
6414
+ }
6415
+ }
6416
+ return { userId: headerUserId, email, name };
6417
+ }
6418
+ const token = extractBearerToken2(request);
6419
+ if (!token) {
6420
+ return unauthorized("User ID not found. Ensure middleware is configured.");
6421
+ }
6422
+ const secret = getConfiguredSecret();
6423
+ let payload = null;
6424
+ if (secret) {
6425
+ payload = await verifyHs256(token, secret);
6426
+ if (!payload) {
6427
+ return unauthorized("Invalid or expired authentication token");
6428
+ }
6429
+ } else if (isStrictMode()) {
6430
+ return unauthorized(
6431
+ "Strict auth mode is enabled but no JWT secret is configured. Set SOLVAPAY_JWT_SECRET or SUPABASE_JWT_SECRET."
6432
+ );
6433
+ } else {
6434
+ payload = decodeJwtUnverified(token);
6435
+ if (!payload) {
6436
+ return unauthorized("Malformed authentication token");
6437
+ }
6438
+ }
6439
+ const userId = typeof payload.sub === "string" ? payload.sub : null;
6440
+ if (!userId) {
6441
+ return unauthorized("Authentication token missing subject (sub) claim");
6302
6442
  }
6303
- const userId = userIdOrError;
6304
- const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
6305
- const name = options.includeName !== false ? await getUserNameFromRequest(request) : null;
6306
6443
  return {
6307
6444
  userId,
6308
- email,
6309
- name
6445
+ email: includeEmail ? pickEmail(payload) : null,
6446
+ name: includeName ? pickName(payload) : null
6310
6447
  };
6311
6448
  } catch (error) {
6312
6449
  return handleRouteError(error, "Get authenticated user", "Authentication failed");
@@ -6701,7 +6838,7 @@ async function activatePlanCore(request, body, options = {}) {
6701
6838
 
6702
6839
  // src/helpers/plans.ts
6703
6840
  var import_core5 = require("@solvapay/core");
6704
- async function listPlansCore(request) {
6841
+ async function listPlansCore(request, options = {}) {
6705
6842
  try {
6706
6843
  const url = new URL(request.url);
6707
6844
  const productRef = url.searchParams.get("productRef");
@@ -6711,19 +6848,20 @@ async function listPlansCore(request) {
6711
6848
  status: 400
6712
6849
  };
6713
6850
  }
6714
- const config = (0, import_core5.getSolvaPayConfig)();
6715
- const solvapaySecretKey = config.apiKey;
6716
- const solvapayApiBaseUrl = config.apiBaseUrl;
6717
- if (!solvapaySecretKey) {
6851
+ const apiClient = options.solvaPay?.apiClient ?? (() => {
6852
+ const config = (0, import_core5.getSolvaPayConfig)();
6853
+ if (!config.apiKey) return null;
6854
+ return createSolvaPayClient({
6855
+ apiKey: config.apiKey,
6856
+ apiBaseUrl: config.apiBaseUrl
6857
+ });
6858
+ })();
6859
+ if (!apiClient) {
6718
6860
  return {
6719
6861
  error: "Server configuration error: SolvaPay secret key not configured",
6720
6862
  status: 500
6721
6863
  };
6722
6864
  }
6723
- const apiClient = createSolvaPayClient({
6724
- apiKey: solvapaySecretKey,
6725
- apiBaseUrl: solvapayApiBaseUrl
6726
- });
6727
6865
  if (!apiClient.listPlans) {
6728
6866
  return {
6729
6867
  error: "List plans method not available",
@@ -6740,6 +6878,159 @@ async function listPlansCore(request) {
6740
6878
  }
6741
6879
  }
6742
6880
 
6881
+ // src/helpers/merchant.ts
6882
+ var import_core6 = require("@solvapay/core");
6883
+ async function getMerchantCore(_request, options = {}) {
6884
+ try {
6885
+ const apiClient = options.solvaPay?.apiClient ?? (() => {
6886
+ const config = (0, import_core6.getSolvaPayConfig)();
6887
+ if (!config.apiKey) return null;
6888
+ return createSolvaPayClient({
6889
+ apiKey: config.apiKey,
6890
+ apiBaseUrl: config.apiBaseUrl
6891
+ });
6892
+ })();
6893
+ if (!apiClient) {
6894
+ return {
6895
+ error: "Server configuration error: SolvaPay secret key not configured",
6896
+ status: 500
6897
+ };
6898
+ }
6899
+ if (!apiClient.getMerchant) {
6900
+ return {
6901
+ error: "Get merchant method not available",
6902
+ status: 500
6903
+ };
6904
+ }
6905
+ const merchant = await apiClient.getMerchant();
6906
+ return merchant;
6907
+ } catch (error) {
6908
+ return handleRouteError(error, "Get merchant", "Failed to fetch merchant");
6909
+ }
6910
+ }
6911
+
6912
+ // src/helpers/product.ts
6913
+ var import_core7 = require("@solvapay/core");
6914
+ async function getProductCore(request, options = {}) {
6915
+ try {
6916
+ const url = new URL(request.url);
6917
+ const productRef = url.searchParams.get("productRef");
6918
+ if (!productRef) {
6919
+ return {
6920
+ error: "Missing required parameter: productRef",
6921
+ status: 400
6922
+ };
6923
+ }
6924
+ const apiClient = options.solvaPay?.apiClient ?? (() => {
6925
+ const config = (0, import_core7.getSolvaPayConfig)();
6926
+ if (!config.apiKey) return null;
6927
+ return createSolvaPayClient({
6928
+ apiKey: config.apiKey,
6929
+ apiBaseUrl: config.apiBaseUrl
6930
+ });
6931
+ })();
6932
+ if (!apiClient) {
6933
+ return {
6934
+ error: "Server configuration error: SolvaPay secret key not configured",
6935
+ status: 500
6936
+ };
6937
+ }
6938
+ if (!apiClient.getProduct) {
6939
+ return {
6940
+ error: "Get product method not available",
6941
+ status: 500
6942
+ };
6943
+ }
6944
+ const product = await apiClient.getProduct(productRef);
6945
+ return product;
6946
+ } catch (error) {
6947
+ return handleRouteError(error, "Get product", "Failed to fetch product");
6948
+ }
6949
+ }
6950
+
6951
+ // src/helpers/purchase.ts
6952
+ async function checkPurchaseCore(request, options = {}) {
6953
+ try {
6954
+ const userResult = await getAuthenticatedUserCore(request, {
6955
+ includeEmail: options.includeEmail,
6956
+ includeName: options.includeName
6957
+ });
6958
+ if (isErrorResult(userResult)) {
6959
+ return userResult;
6960
+ }
6961
+ const { userId, email, name } = userResult;
6962
+ const solvaPay = options.solvaPay || createSolvaPay();
6963
+ const cachedCustomerRef = request.headers.get("x-solvapay-customer-ref");
6964
+ if (cachedCustomerRef) {
6965
+ try {
6966
+ const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
6967
+ if (customer && customer.customerRef) {
6968
+ if (customer.externalRef && customer.externalRef === userId) {
6969
+ const filteredPurchases = (customer.purchases || []).filter(
6970
+ (p) => p.status === "active"
6971
+ );
6972
+ return {
6973
+ customerRef: customer.customerRef,
6974
+ email: customer.email,
6975
+ name: customer.name,
6976
+ purchases: filteredPurchases
6977
+ };
6978
+ }
6979
+ }
6980
+ } catch {
6981
+ }
6982
+ }
6983
+ try {
6984
+ const customerRef = await solvaPay.ensureCustomer(userId, userId, {
6985
+ email: email || void 0,
6986
+ name: name || void 0
6987
+ });
6988
+ const customer = await solvaPay.getCustomer({ customerRef });
6989
+ const filteredPurchases = (customer.purchases || []).filter((p) => p.status === "active");
6990
+ return {
6991
+ customerRef: customer.customerRef || userId,
6992
+ email: customer.email,
6993
+ name: customer.name,
6994
+ purchases: filteredPurchases
6995
+ };
6996
+ } catch {
6997
+ return {
6998
+ customerRef: userId,
6999
+ purchases: []
7000
+ };
7001
+ }
7002
+ } catch (error) {
7003
+ return handleRouteError(error, "Check purchase", "Failed to check purchase");
7004
+ }
7005
+ }
7006
+
7007
+ // src/helpers/usage.ts
7008
+ async function trackUsageCore(request, body, options = {}) {
7009
+ try {
7010
+ const userResult = await getAuthenticatedUserCore(request);
7011
+ if (isErrorResult(userResult)) {
7012
+ return userResult;
7013
+ }
7014
+ const { userId, email, name } = userResult;
7015
+ const solvaPay = options.solvaPay || createSolvaPay();
7016
+ const customerRef = await solvaPay.ensureCustomer(userId, userId, {
7017
+ email: email || void 0,
7018
+ name: name || void 0
7019
+ });
7020
+ await solvaPay.trackUsage({
7021
+ customerRef,
7022
+ actionType: body.actionType,
7023
+ units: body.units,
7024
+ productRef: body.productRef,
7025
+ description: body.description,
7026
+ metadata: body.metadata
7027
+ });
7028
+ return { success: true };
7029
+ } catch (error) {
7030
+ return handleRouteError(error, "Track usage", "Track usage failed");
7031
+ }
7032
+ }
7033
+
6743
7034
  // src/index.ts
6744
7035
  function verifyWebhook({
6745
7036
  body,
@@ -6747,34 +7038,34 @@ function verifyWebhook({
6747
7038
  secret
6748
7039
  }) {
6749
7040
  const toleranceSec = 300;
6750
- if (!signature) throw new import_core6.SolvaPayError("Missing webhook signature");
7041
+ if (!signature) throw new import_core8.SolvaPayError("Missing webhook signature");
6751
7042
  const parts = signature.split(",");
6752
7043
  const tPart = parts.find((p) => p.startsWith("t="));
6753
7044
  const v1Part = parts.find((p) => p.startsWith("v1="));
6754
7045
  if (!tPart || !v1Part) {
6755
- throw new import_core6.SolvaPayError("Malformed webhook signature");
7046
+ throw new import_core8.SolvaPayError("Malformed webhook signature");
6756
7047
  }
6757
7048
  const timestamp = parseInt(tPart.slice(2), 10);
6758
7049
  const receivedHmac = v1Part.slice(3);
6759
7050
  if (Number.isNaN(timestamp) || !receivedHmac) {
6760
- throw new import_core6.SolvaPayError("Malformed webhook signature");
7051
+ throw new import_core8.SolvaPayError("Malformed webhook signature");
6761
7052
  }
6762
7053
  if (toleranceSec > 0) {
6763
7054
  const age = Math.abs(Math.floor(Date.now() / 1e3) - timestamp);
6764
7055
  if (age > toleranceSec) {
6765
- throw new import_core6.SolvaPayError("Webhook signature timestamp too old");
7056
+ throw new import_core8.SolvaPayError("Webhook signature timestamp too old");
6766
7057
  }
6767
7058
  }
6768
7059
  const expectedHmac = import_node_crypto.default.createHmac("sha256", secret).update(`${timestamp}.${body}`).digest("hex");
6769
7060
  if (receivedHmac.length !== expectedHmac.length) {
6770
- throw new import_core6.SolvaPayError("Invalid webhook signature");
7061
+ throw new import_core8.SolvaPayError("Invalid webhook signature");
6771
7062
  }
6772
7063
  const ok = import_node_crypto.default.timingSafeEqual(Buffer.from(expectedHmac), Buffer.from(receivedHmac));
6773
- if (!ok) throw new import_core6.SolvaPayError("Invalid webhook signature");
7064
+ if (!ok) throw new import_core8.SolvaPayError("Invalid webhook signature");
6774
7065
  try {
6775
7066
  return JSON.parse(body);
6776
7067
  } catch {
6777
- throw new import_core6.SolvaPayError("Invalid webhook payload: body is not valid JSON");
7068
+ throw new import_core8.SolvaPayError("Invalid webhook payload: body is not valid JSON");
6778
7069
  }
6779
7070
  }
6780
7071
  // Annotate the CommonJS export names for ESM import in node:
@@ -6785,6 +7076,7 @@ function verifyWebhook({
6785
7076
  activatePlanCore,
6786
7077
  buildAuthInfoFromBearer,
6787
7078
  cancelPurchaseCore,
7079
+ checkPurchaseCore,
6788
7080
  createCheckoutSessionCore,
6789
7081
  createCustomerSessionCore,
6790
7082
  createMcpOAuthBridge,
@@ -6799,8 +7091,10 @@ function verifyWebhook({
6799
7091
  getCustomerBalanceCore,
6800
7092
  getCustomerRefFromBearerAuthHeader,
6801
7093
  getCustomerRefFromJwtPayload,
7094
+ getMerchantCore,
6802
7095
  getOAuthAuthorizationServerResponse,
6803
7096
  getOAuthProtectedResourceResponse,
7097
+ getProductCore,
6804
7098
  handleRouteError,
6805
7099
  isErrorResult,
6806
7100
  jsonSchemaToZodRawShape,
@@ -6810,6 +7104,7 @@ function verifyWebhook({
6810
7104
  reactivatePurchaseCore,
6811
7105
  registerVirtualToolsMcpImpl,
6812
7106
  syncCustomerCore,
7107
+ trackUsageCore,
6813
7108
  verifyWebhook,
6814
7109
  withRetry
6815
7110
  });
package/dist/index.d.cts CHANGED
@@ -2488,6 +2488,26 @@ interface ProcessPaymentResult {
2488
2488
  status: 'completed';
2489
2489
  }
2490
2490
  type ActivatePlanResult = components['schemas']['ActivatePlanResponseDto'];
2491
+ /**
2492
+ * SDK-facing merchant identity (source: GET /v1/sdk/merchant).
2493
+ *
2494
+ * Hand-typed here until the OpenAPI generator picks up the new endpoint.
2495
+ * Fields match `SdkMerchantResponseDto` on the backend.
2496
+ */
2497
+ type SdkMerchantResponse = {
2498
+ displayName: string;
2499
+ legalName: string;
2500
+ supportEmail?: string;
2501
+ supportUrl?: string;
2502
+ termsUrl?: string;
2503
+ privacyUrl?: string;
2504
+ country?: string;
2505
+ defaultCurrency?: string;
2506
+ statementDescriptor?: string;
2507
+ logoUrl?: string;
2508
+ };
2509
+ /** SDK-facing product projection. Sourced from the existing OpenAPI spec. */
2510
+ type SdkProductResponse = components['schemas']['SdkProductResponse'];
2491
2511
  type McpBootstrapPlanInput = NonNullable<components['schemas']['McpBootstrapDto']['plans']>[number];
2492
2512
  type ToolPlanMappingInput = NonNullable<components['schemas']['McpBootstrapDto']['tools']>[number];
2493
2513
  type McpBootstrapRequest = components['schemas']['McpBootstrapDto'];
@@ -2556,6 +2576,13 @@ interface SolvaPayClient {
2556
2576
  externalRef?: string;
2557
2577
  email?: string;
2558
2578
  }): Promise<CustomerResponseMapped>;
2579
+ /**
2580
+ * SDK-facing merchant identity (GET /v1/sdk/merchant).
2581
+ * Returns the subset of provider fields safe for browser consumption —
2582
+ * used by `<MandateText>`, `<CheckoutSummary>`, and trust signals.
2583
+ */
2584
+ getMerchant?(): Promise<SdkMerchantResponse>;
2585
+ getProduct?(productRef: string): Promise<SdkProductResponse>;
2559
2586
  listProducts?(): Promise<Array<{
2560
2587
  reference: string;
2561
2588
  name: string;
@@ -3785,8 +3812,16 @@ declare function handleRouteError(error: unknown, operationName: string, default
3785
3812
  * and name from authenticated requests. Works with any framework that uses
3786
3813
  * the standard Web API Request (Express, Fastify, Next.js, Edge Functions, etc.).
3787
3814
  *
3788
- * Uses dynamic imports to avoid requiring @solvapay/auth at build time,
3789
- * making it suitable for edge runtime environments.
3815
+ * Resolution order:
3816
+ * 1. `x-user-id` header set by Next.js-style middleware (unchanged).
3817
+ * 2. `Authorization: Bearer <jwt>` — verified via HS256 when a secret is
3818
+ * configured (`SOLVAPAY_JWT_SECRET` or `SUPABASE_JWT_SECRET`), or
3819
+ * unverified-decoded when no secret is configured. The unverified path
3820
+ * covers platforms that verify JWTs at the gateway (e.g. Supabase Edge
3821
+ * with `verify_jwt = true`, which is the default) and asymmetric signing
3822
+ * keys (ES256/RS256) that the SDK does not have keys for.
3823
+ * 3. Set `SOLVAPAY_AUTH_STRICT=true` to require cryptographic verification
3824
+ * inside the handler (the unverified-decode fallback is then disabled).
3790
3825
  *
3791
3826
  * @param request - Standard Web API Request object
3792
3827
  * @param options - Configuration options
@@ -4116,13 +4151,85 @@ declare function activatePlanCore(request: Request, body: {
4116
4151
 
4117
4152
  type Plan = components['schemas']['Plan'];
4118
4153
  /**
4119
- * List plans - core implementation
4154
+ * List plans - core implementation.
4155
+ *
4156
+ * Pass `options.solvaPay` to route through a pre-configured SolvaPay instance
4157
+ * (e.g. stub-backed in examples). When omitted, the helper reads
4158
+ * `SOLVAPAY_SECRET_KEY` from environment and constructs a real API client.
4120
4159
  */
4121
- declare function listPlansCore(request: Request): Promise<{
4160
+ declare function listPlansCore(request: Request, options?: {
4161
+ solvaPay?: SolvaPay;
4162
+ }): Promise<{
4122
4163
  plans: Plan[];
4123
4164
  productRef: string;
4124
4165
  } | ErrorResult>;
4125
4166
 
4167
+ /**
4168
+ * Merchant Helper (Core)
4169
+ *
4170
+ * Generic helper for GET /api/merchant — returns the SDK-facing merchant
4171
+ * identity used by `<MandateText>`, `<CheckoutSummary>`, and trust signals.
4172
+ * Works with standard Web API Request (Express, Fastify, Next.js, Edge).
4173
+ */
4174
+
4175
+ declare function getMerchantCore(_request: Request, options?: {
4176
+ solvaPay?: SolvaPay;
4177
+ }): Promise<SdkMerchantResponse | ErrorResult>;
4178
+
4179
+ /**
4180
+ * Product Helper (Core)
4181
+ *
4182
+ * Generic helper for GET /api/get-product?productRef=...
4183
+ * Returns a single product by reference, used by the `useProduct` React hook.
4184
+ */
4185
+
4186
+ declare function getProductCore(request: Request, options?: {
4187
+ solvaPay?: SolvaPay;
4188
+ }): Promise<SdkProductResponse | ErrorResult>;
4189
+
4190
+ interface PurchaseCheckResult {
4191
+ customerRef: string;
4192
+ email?: string;
4193
+ name?: string;
4194
+ purchases: Array<{
4195
+ reference: string;
4196
+ productName?: string;
4197
+ productRef?: string;
4198
+ status?: string;
4199
+ startDate?: string;
4200
+ planSnapshot?: {
4201
+ meterId?: string;
4202
+ limit?: number;
4203
+ freeUnits?: number;
4204
+ };
4205
+ usage?: {
4206
+ used?: number;
4207
+ overageUnits?: number;
4208
+ overageCost?: number;
4209
+ periodStart?: string;
4210
+ periodEnd?: string;
4211
+ };
4212
+ [key: string]: unknown;
4213
+ }>;
4214
+ }
4215
+ declare function checkPurchaseCore(request: Request, options?: {
4216
+ solvaPay?: SolvaPay;
4217
+ includeEmail?: boolean;
4218
+ includeName?: boolean;
4219
+ }): Promise<PurchaseCheckResult | ErrorResult>;
4220
+
4221
+ declare function trackUsageCore(request: Request, body: {
4222
+ actionType?: 'transaction' | 'api_call' | 'hour' | 'email' | 'storage' | 'custom';
4223
+ units?: number;
4224
+ productRef?: string;
4225
+ description?: string;
4226
+ metadata?: Record<string, unknown>;
4227
+ }, options?: {
4228
+ solvaPay?: SolvaPay;
4229
+ }): Promise<{
4230
+ success: true;
4231
+ } | ErrorResult>;
4232
+
4126
4233
  /**
4127
4234
  * SolvaPay Server SDK
4128
4235
  *
@@ -4178,4 +4285,4 @@ declare function verifyWebhook({ body, signature, secret, }: {
4178
4285
  secret: string;
4179
4286
  }): WebhookEvent;
4180
4287
 
4181
- export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type McpAdapterOptions, McpBearerAuthError, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpServerLike, type McpToolExtra, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableFunction, type PayableOptions, type PaywallArgs, PaywallError, type PaywallMetadata, type PaywallStructuredContent, type PaywallToolResult, type ProcessPaymentResult, type RegisterVirtualToolsMcpOptions, type RetryOptions, type ServerClientOptions, type SolvaPay, type SolvaPayClient, type ToolPlanMappingInput, VIRTUAL_TOOL_DEFINITIONS, type VirtualToolDefinition, type VirtualToolsOptions, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, buildAuthInfoFromBearer, cancelPurchaseCore, type components, createCheckoutSessionCore, createCustomerSessionCore, createMcpOAuthBridge, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, createVirtualTools, decodeJwtPayload, extractBearerToken, getAuthenticatedUserCore, getCustomerBalanceCore, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, handleRouteError, isErrorResult, jsonSchemaToZodRawShape, listPlansCore, paywallErrorToClientPayload, processPaymentIntentCore, reactivatePurchaseCore, registerVirtualToolsMcpImpl, syncCustomerCore, verifyWebhook, withRetry };
4288
+ export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type McpAdapterOptions, McpBearerAuthError, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpServerLike, type McpToolExtra, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableFunction, type PayableOptions, type PaywallArgs, PaywallError, type PaywallMetadata, type PaywallStructuredContent, type PaywallToolResult, type ProcessPaymentResult, type PurchaseCheckResult, type RegisterVirtualToolsMcpOptions, type RetryOptions, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, type ToolPlanMappingInput, VIRTUAL_TOOL_DEFINITIONS, type VirtualToolDefinition, type VirtualToolsOptions, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, buildAuthInfoFromBearer, cancelPurchaseCore, checkPurchaseCore, type components, createCheckoutSessionCore, createCustomerSessionCore, createMcpOAuthBridge, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, createVirtualTools, decodeJwtPayload, extractBearerToken, getAuthenticatedUserCore, getCustomerBalanceCore, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getMerchantCore, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, getProductCore, handleRouteError, isErrorResult, jsonSchemaToZodRawShape, listPlansCore, paywallErrorToClientPayload, processPaymentIntentCore, reactivatePurchaseCore, registerVirtualToolsMcpImpl, syncCustomerCore, trackUsageCore, verifyWebhook, withRetry };