@weftlabs/sdk 0.29.0 → 0.31.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/dist/index.js CHANGED
@@ -1892,6 +1892,9 @@ var FetchErrorResponseErrorEnum = {
1892
1892
  UnknownParameter: "UNKNOWN_PARAMETER",
1893
1893
  InvalidUrl: "INVALID_URL",
1894
1894
  InvalidMaxCostUsd: "INVALID_MAX_COST_USD",
1895
+ InvalidAllowTempoRefill: "INVALID_ALLOW_TEMPO_REFILL",
1896
+ InvalidMaxTotalCostUsd: "INVALID_MAX_TOTAL_COST_USD",
1897
+ IncompatibleFetchControls: "INCOMPATIBLE_FETCH_CONTROLS",
1895
1898
  UnsupportedMethod: "UNSUPPORTED_METHOD",
1896
1899
  InvalidBody: "INVALID_BODY",
1897
1900
  InvalidHeaders: "INVALID_HEADERS",
@@ -1899,6 +1902,7 @@ var FetchErrorResponseErrorEnum = {
1899
1902
  IdempotencyConflict: "IDEMPOTENCY_CONFLICT",
1900
1903
  AccountClosing: "ACCOUNT_CLOSING",
1901
1904
  ExceededMaxCost: "EXCEEDED_MAX_COST",
1905
+ TotalCostUnverifiable: "TOTAL_COST_UNVERIFIABLE",
1902
1906
  FundingPending: "FUNDING_PENDING",
1903
1907
  InsufficientBalance: "INSUFFICIENT_BALANCE",
1904
1908
  PaymentAuthorizationRequired: "PAYMENT_AUTHORIZATION_REQUIRED",
@@ -2083,6 +2087,8 @@ function FetchRequestFromJSONTyped(json, ignoreDiscriminator) {
2083
2087
  return {
2084
2088
  "url": json["url"],
2085
2089
  "maxCostUsd": json["max_cost_usd"] == null ? void 0 : json["max_cost_usd"],
2090
+ "allowTempoRefill": json["allow_tempo_refill"] == null ? void 0 : json["allow_tempo_refill"],
2091
+ "maxTotalCostUsd": json["max_total_cost_usd"] == null ? void 0 : json["max_total_cost_usd"],
2086
2092
  "method": json["method"] == null ? void 0 : json["method"],
2087
2093
  "body": json["body"] == null ? void 0 : FetchRequestBodyFromJSON(json["body"]),
2088
2094
  "headers": json["headers"] == null ? void 0 : json["headers"],
@@ -2101,6 +2107,8 @@ function FetchRequestToJSONTyped(value, ignoreDiscriminator = false) {
2101
2107
  return {
2102
2108
  "url": value["url"],
2103
2109
  "max_cost_usd": value["maxCostUsd"],
2110
+ "allow_tempo_refill": value["allowTempoRefill"],
2111
+ "max_total_cost_usd": value["maxTotalCostUsd"],
2104
2112
  "method": value["method"],
2105
2113
  "body": FetchRequestBodyToJSON(value["body"]),
2106
2114
  "headers": value["headers"],
@@ -4605,7 +4613,7 @@ var DocumentationApi = class extends BaseAPI {
4605
4613
  // src/generated/apis/FetchApi.ts
4606
4614
  var FetchApi = class extends BaseAPI {
4607
4615
  /**
4608
- * Universal x402/MPP fetch proxy. The caller provides a target `url`, a hard `max_cost_usd` ceiling, and optional `method` / `body` / `headers`. Weft: 1. Issues the request. 2. On `402 Payment Required`, selects a supported x402 or MPP challenge. 3. Compares the asking price to `max_cost_usd` and the buyer\'s policy (`max_tx_usd`, daily/weekly limits). 4. If an eligible mainnet MPP challenge finds its Tempo token short, creates or adopts a buyer-owned Base-to-Tempo refill and returns `409 FUNDING_PENDING` with `details.reason=funding_active`. If an overlapping payment invalidates the balance observation before a bridge is created, the same retryable response carries `details.reason=balance_changed`. The caller retries the identical fetch after `details.retry_after_seconds`; that later request obtains a fresh challenge and reruns rail selection and all payment controls. 5. Authorizes payment from the buyer\'s wallet on the selected rail. 6. Replays the request with the protocol-specific payment credential. 7. Streams the upstream artifact back, base64-encoded under `body_base64`, with `paid_usd`, `held_usd`, `payment_status`, `tx_hash`, and `protocol`. `paid_usd` is \"0.00\" until the charge is CONFIRMED settled — a signed-but- unsettled hold (the common case for x402, which settles asynchronously) reports its amount in `held_usd` instead, never in `paid_usd`. Errors are structured with a stable `error` code, and each error response carries the buyer\'s `policy`, `balance`, and a `dashboard_url` so a CLI can render an actionable message without a second round-trip. Account-scoped: the bearer must be a buyer-scoped API key, an OAuth access token carrying `fetch`, or a claimed `wbt_*` bearer. **Forwarded headers:** the caller\'s `headers` are passed through to the upstream, except a denylist of hop-by-hop and Weft-internal headers (`host`, `authorization`, `cookie`, `proxy-authorization`, `x-forwarded-*`, `x-real-ip`, `x-payment`, `connection`, `upgrade`). Up to 32 headers, 4 KB of combined value bytes.
4616
+ * Universal x402/MPP fetch proxy. The caller provides a target `url`, a merchant-principal `max_cost_usd` ceiling, and optional `method` / `body` / `headers`. Weft: 1. Issues the request. 2. On `402 Payment Required`, selects a supported x402 or MPP challenge. 3. Compares the asking price to `max_cost_usd` and the buyer\'s policy (`max_tx_usd`, daily/weekly limits). 4. If refill is allowed and an eligible mainnet MPP challenge finds its Tempo token short, creates or adopts a buyer-owned Base-to-Tempo refill and returns `409 FUNDING_PENDING` with `details.reason=funding_active`. If an overlapping payment invalidates the balance observation before a bridge is created, the same retryable response carries `details.reason=balance_changed`. The caller retries the identical fetch after `details.retry_after_seconds`; that later request obtains a fresh challenge and reruns rail selection and all payment controls. 5. Authorizes payment from the buyer\'s wallet on the selected rail. 6. Replays the request with the protocol-specific payment credential. 7. Streams the upstream artifact back, base64-encoded under `body_base64`, with `paid_usd`, `held_usd`, `payment_status`, `tx_hash`, and `protocol`. `paid_usd` is \"0.00\" until the charge is CONFIRMED settled — a signed-but- unsettled hold (the common case for x402, which settles asynchronously) reports its amount in `held_usd` instead, never in `paid_usd`. **Opt-in safety controls:** `allow_tempo_refill: false` prevents this request from creating, adopting, or enqueueing a Base-to-Tempo bridge. A Tempo shortfall returns `402 INSUFFICIENT_BALANCE`; unrelated bridges and their jobs remain unchanged. `access_method_id` is advisory and does not enforce a payment rail. `max_total_cost_usd` is an all-in ceiling covering merchant principal, network gas, provider fees, and prerequisite buyer-paid operations. It disables refill; explicitly combining it with `allow_tempo_refill: true` returns `422 INCOMPATIBLE_FETCH_CONTROLS`. Current wallet integrations provide no supported binding all-in fee guarantee. Therefore all-in requests return `402 TOTAL_COST_UNVERIFIABLE` before payment preparation, approval, reservation, or refill. This also refuses recovery of older payments and SIWX wallet signing; it admits no positive paid route. Increasing the ceiling does not resolve missing fee authority. Omitted controls preserve existing behavior. Ordinary non-402 merchant responses retain `MERCHANT_RETURNED_NON_402`. Stored-result replay is historical payment information, not a new bounded authorization. Errors are structured with a stable `error` code, and each error response carries the buyer\'s `policy`, `balance`, and a `dashboard_url` so a CLI can render an actionable message without a second round-trip. Account-scoped: the bearer must be a buyer-scoped API key, an OAuth access token carrying `fetch`, or a claimed `wbt_*` bearer. **Forwarded headers:** the caller\'s `headers` are passed through to the upstream, except a denylist of hop-by-hop and Weft-internal headers (`host`, `authorization`, `cookie`, `proxy-authorization`, `x-forwarded-*`, `x-real-ip`, `x-payment`, `connection`, `upgrade`). Up to 32 headers, 4 KB of combined value bytes.
4609
4617
  * Pay-and-fetch any URL (x402/MPP proxy)
4610
4618
  */
4611
4619
  async fetchRaw(requestParameters, initOverrides) {
@@ -4639,7 +4647,7 @@ var FetchApi = class extends BaseAPI {
4639
4647
  return new JSONApiResponse(response, (jsonValue) => FetchResponseFromJSON(jsonValue));
4640
4648
  }
4641
4649
  /**
4642
- * Universal x402/MPP fetch proxy. The caller provides a target `url`, a hard `max_cost_usd` ceiling, and optional `method` / `body` / `headers`. Weft: 1. Issues the request. 2. On `402 Payment Required`, selects a supported x402 or MPP challenge. 3. Compares the asking price to `max_cost_usd` and the buyer\'s policy (`max_tx_usd`, daily/weekly limits). 4. If an eligible mainnet MPP challenge finds its Tempo token short, creates or adopts a buyer-owned Base-to-Tempo refill and returns `409 FUNDING_PENDING` with `details.reason=funding_active`. If an overlapping payment invalidates the balance observation before a bridge is created, the same retryable response carries `details.reason=balance_changed`. The caller retries the identical fetch after `details.retry_after_seconds`; that later request obtains a fresh challenge and reruns rail selection and all payment controls. 5. Authorizes payment from the buyer\'s wallet on the selected rail. 6. Replays the request with the protocol-specific payment credential. 7. Streams the upstream artifact back, base64-encoded under `body_base64`, with `paid_usd`, `held_usd`, `payment_status`, `tx_hash`, and `protocol`. `paid_usd` is \"0.00\" until the charge is CONFIRMED settled — a signed-but- unsettled hold (the common case for x402, which settles asynchronously) reports its amount in `held_usd` instead, never in `paid_usd`. Errors are structured with a stable `error` code, and each error response carries the buyer\'s `policy`, `balance`, and a `dashboard_url` so a CLI can render an actionable message without a second round-trip. Account-scoped: the bearer must be a buyer-scoped API key, an OAuth access token carrying `fetch`, or a claimed `wbt_*` bearer. **Forwarded headers:** the caller\'s `headers` are passed through to the upstream, except a denylist of hop-by-hop and Weft-internal headers (`host`, `authorization`, `cookie`, `proxy-authorization`, `x-forwarded-*`, `x-real-ip`, `x-payment`, `connection`, `upgrade`). Up to 32 headers, 4 KB of combined value bytes.
4650
+ * Universal x402/MPP fetch proxy. The caller provides a target `url`, a merchant-principal `max_cost_usd` ceiling, and optional `method` / `body` / `headers`. Weft: 1. Issues the request. 2. On `402 Payment Required`, selects a supported x402 or MPP challenge. 3. Compares the asking price to `max_cost_usd` and the buyer\'s policy (`max_tx_usd`, daily/weekly limits). 4. If refill is allowed and an eligible mainnet MPP challenge finds its Tempo token short, creates or adopts a buyer-owned Base-to-Tempo refill and returns `409 FUNDING_PENDING` with `details.reason=funding_active`. If an overlapping payment invalidates the balance observation before a bridge is created, the same retryable response carries `details.reason=balance_changed`. The caller retries the identical fetch after `details.retry_after_seconds`; that later request obtains a fresh challenge and reruns rail selection and all payment controls. 5. Authorizes payment from the buyer\'s wallet on the selected rail. 6. Replays the request with the protocol-specific payment credential. 7. Streams the upstream artifact back, base64-encoded under `body_base64`, with `paid_usd`, `held_usd`, `payment_status`, `tx_hash`, and `protocol`. `paid_usd` is \"0.00\" until the charge is CONFIRMED settled — a signed-but- unsettled hold (the common case for x402, which settles asynchronously) reports its amount in `held_usd` instead, never in `paid_usd`. **Opt-in safety controls:** `allow_tempo_refill: false` prevents this request from creating, adopting, or enqueueing a Base-to-Tempo bridge. A Tempo shortfall returns `402 INSUFFICIENT_BALANCE`; unrelated bridges and their jobs remain unchanged. `access_method_id` is advisory and does not enforce a payment rail. `max_total_cost_usd` is an all-in ceiling covering merchant principal, network gas, provider fees, and prerequisite buyer-paid operations. It disables refill; explicitly combining it with `allow_tempo_refill: true` returns `422 INCOMPATIBLE_FETCH_CONTROLS`. Current wallet integrations provide no supported binding all-in fee guarantee. Therefore all-in requests return `402 TOTAL_COST_UNVERIFIABLE` before payment preparation, approval, reservation, or refill. This also refuses recovery of older payments and SIWX wallet signing; it admits no positive paid route. Increasing the ceiling does not resolve missing fee authority. Omitted controls preserve existing behavior. Ordinary non-402 merchant responses retain `MERCHANT_RETURNED_NON_402`. Stored-result replay is historical payment information, not a new bounded authorization. Errors are structured with a stable `error` code, and each error response carries the buyer\'s `policy`, `balance`, and a `dashboard_url` so a CLI can render an actionable message without a second round-trip. Account-scoped: the bearer must be a buyer-scoped API key, an OAuth access token carrying `fetch`, or a claimed `wbt_*` bearer. **Forwarded headers:** the caller\'s `headers` are passed through to the upstream, except a denylist of hop-by-hop and Weft-internal headers (`host`, `authorization`, `cookie`, `proxy-authorization`, `x-forwarded-*`, `x-real-ip`, `x-payment`, `connection`, `upgrade`). Up to 32 headers, 4 KB of combined value bytes.
4643
4651
  * Pay-and-fetch any URL (x402/MPP proxy)
4644
4652
  */
4645
4653
  async fetch(requestParameters, initOverrides) {
@@ -4880,6 +4888,26 @@ var SearchApi = class extends BaseAPI {
4880
4888
  };
4881
4889
 
4882
4890
  // src/error.ts
4891
+ var PRE_SIGN_FETCH_CODES = /* @__PURE__ */ new Set([
4892
+ "EXCEEDED_MAX_COST",
4893
+ "MERCHANT_RETURNED_NON_402",
4894
+ "INSUFFICIENT_BALANCE",
4895
+ "DENYLISTED_RECIPIENT",
4896
+ "WALLET_ENVIRONMENT_MISMATCH",
4897
+ "UNSUPPORTED_ASSET",
4898
+ "INVALID_REQUEST",
4899
+ "UNKNOWN_PARAMETER",
4900
+ "INVALID_URL",
4901
+ "INVALID_MAX_COST_USD",
4902
+ "UNSUPPORTED_METHOD",
4903
+ "INVALID_BODY",
4904
+ "INVALID_HEADERS",
4905
+ "INVALID_IDEMPOTENCY_KEY"
4906
+ ]);
4907
+ function fetchCharge(status, code) {
4908
+ const preSign = PRE_SIGN_FETCH_CODES.has(code) || code.startsWith("POLICY_VIOLATION_");
4909
+ return status >= 400 && status < 500 && preSign ? "none" : "possible";
4910
+ }
4883
4911
  var WeftError = class extends Error {
4884
4912
  constructor(options) {
4885
4913
  super(options.message);
@@ -4889,19 +4917,32 @@ var WeftError = class extends Error {
4889
4917
  this.requestId = options.requestId;
4890
4918
  this.retryable = options.retryable;
4891
4919
  this.details = options.details;
4920
+ this.charge = options.charge ?? "possible";
4892
4921
  }
4893
4922
  };
4894
- async function normalizeWeftError(error) {
4923
+ async function normalizeWeftError(error, paid = false) {
4895
4924
  if (error instanceof FetchError) {
4896
4925
  return new WeftError({
4897
4926
  status: 0,
4898
4927
  code: "NETWORK_ERROR",
4899
4928
  message: `Network failure before a Weft API response: ${error.cause?.message ?? error.message}`,
4900
4929
  retryable: true,
4901
- details: error.cause
4930
+ details: error.cause,
4931
+ charge: paid ? "possible" : "none"
4932
+ });
4933
+ }
4934
+ if (!(error instanceof ResponseError)) {
4935
+ if (!paid || error instanceof WeftError) return error;
4936
+ return new WeftError({
4937
+ status: 0,
4938
+ code: "RESPONSE_DECODE_ERROR",
4939
+ message: "Weft API returned a fetch response that could not be decoded",
4940
+ // A replay returns the same body; reconcile instead of retrying.
4941
+ retryable: false,
4942
+ details: error,
4943
+ charge: "possible"
4902
4944
  });
4903
4945
  }
4904
- if (!(error instanceof ResponseError)) return error;
4905
4946
  let details;
4906
4947
  try {
4907
4948
  details = await error.response.json();
@@ -4911,13 +4952,15 @@ async function normalizeWeftError(error) {
4911
4952
  const body = details;
4912
4953
  const nested = typeof body?.error === "object" ? body.error : void 0;
4913
4954
  const status = error.response.status;
4955
+ const code = nested?.code ?? body?.code ?? (typeof body?.error === "string" ? body.error : `HTTP_${status}`);
4914
4956
  return new WeftError({
4915
4957
  status,
4916
- code: nested?.code ?? body?.code ?? (typeof body?.error === "string" ? body.error : `HTTP_${status}`),
4958
+ code,
4917
4959
  message: nested?.message ?? body?.message ?? `Weft API returned HTTP ${status}`,
4918
4960
  requestId: nested?.request_id ?? body?.request_id ?? error.response.headers.get("x-request-id") ?? void 0,
4919
4961
  retryable: status === 429 || status >= 500,
4920
- details
4962
+ details,
4963
+ charge: paid ? fetchCharge(status, String(code)) : "none"
4921
4964
  });
4922
4965
  }
4923
4966
 
@@ -4955,11 +4998,11 @@ var WeftClient = class {
4955
4998
  this.fetches = new FetchApi(configuration);
4956
4999
  this.purchaseHistory = new PurchasesApi(configuration);
4957
5000
  }
4958
- async call(operation) {
5001
+ async call(operation, paid = false) {
4959
5002
  try {
4960
5003
  return await operation();
4961
5004
  } catch (error) {
4962
- throw await normalizeWeftError(error);
5005
+ throw await normalizeWeftError(error, paid);
4963
5006
  }
4964
5007
  }
4965
5008
  me() {
@@ -4978,12 +5021,27 @@ var WeftClient = class {
4978
5021
  if (!options.idempotencyKey.trim()) {
4979
5022
  throw new Error("idempotencyKey is required");
4980
5023
  }
5024
+ if (!/^[!-~]{1,255}$/.test(options.idempotencyKey)) {
5025
+ throw new Error(
5026
+ "idempotencyKey must be 1-255 visible ASCII characters without spaces"
5027
+ );
5028
+ }
5029
+ const fetchRequest = request.body != null && typeof request.body === "object" ? { ...request, body: JSON.stringify(request.body) } : request;
4981
5030
  return this.call(
4982
5031
  () => this.fetches.fetch({
4983
- fetchRequest: request,
5032
+ fetchRequest,
4984
5033
  idempotencyKey: options.idempotencyKey
4985
- })
4986
- );
5034
+ }),
5035
+ true
5036
+ ).then(async (response) => {
5037
+ if (typeof response?.status !== "number") {
5038
+ throw await normalizeWeftError(
5039
+ new Error("unreadable fetch response"),
5040
+ true
5041
+ );
5042
+ }
5043
+ return response;
5044
+ });
4987
5045
  }
4988
5046
  purchases(options = {}) {
4989
5047
  return this.call(() => this.purchaseHistory.listPurchases(options));