weft-sdk 0.25.0 → 0.32.5
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.
- checksums.yaml +4 -4
- data/docs/FetchApi.md +3 -3
- data/docs/FetchErrorResponse.md +1 -1
- data/docs/FetchRequest.md +6 -2
- data/docs/FetchResponse.md +5 -3
- data/docs/GetPurchaseIdParameter.md +48 -0
- data/docs/PaymentsApi.md +2 -0
- data/docs/Purchase.md +6 -0
- data/docs/PurchasesApi.md +2 -2
- data/docs/SearchApi.md +1 -1
- data/docs/SearchCompactAccess.md +23 -0
- data/docs/SearchCompactAccessPrice.md +23 -0
- data/docs/SearchCompactNextCall.md +23 -0
- data/docs/SearchCompactResult.md +47 -0
- data/docs/SearchCompactResultAttribution.md +21 -0
- data/docs/SearchCompactResultBlockedScopesInner.md +19 -0
- data/docs/SearchCompactResultOperation.md +21 -0
- data/docs/SearchCompactResultProvider.md +19 -0
- data/docs/SearchEndpointCall.md +1 -1
- data/docs/SearchEndpointCallInputSchema.md +14 -0
- data/docs/SearchEndpointHit.md +5 -1
- data/docs/SearchHelperDocs.md +23 -0
- data/docs/SearchRequest.md +3 -1
- data/docs/SearchResponse.md +9 -3
- data/docs/SearchWeftFetchCompatibility.md +3 -1
- data/docs/WebhooksApi.md +414 -0
- data/lib/weft/client.rb +271 -0
- data/lib/weft/error.rb +41 -0
- data/lib/weft/facilitator/client.rb +254 -42
- data/lib/weft/facilitator/echo.rb +99 -0
- data/lib/weft/facilitator/extensions.rb +183 -0
- data/lib/weft/facilitator/fee.rb +26 -11
- data/lib/weft/facilitator/handshake.rb +92 -0
- data/lib/weft/facilitator/json_wire.rb +74 -0
- data/lib/weft/facilitator/middleware.rb +563 -137
- data/lib/weft/facilitator/path_match.rb +179 -0
- data/lib/weft/facilitator/product.rb +380 -0
- data/lib/weft/facilitator/replay.rb +46 -0
- data/lib/weft/facilitator/settlement.rb +117 -0
- data/lib/weft/facilitator/x402.rb +355 -0
- data/lib/weft/generated/api/account_api.rb +2 -2
- data/lib/weft/generated/api/agent_bootstrap_api.rb +2 -2
- data/lib/weft/generated/api/api_keys_api.rb +2 -2
- data/lib/weft/generated/api/auth_api.rb +2 -2
- data/lib/weft/generated/api/balance_api.rb +2 -2
- data/lib/weft/generated/api/documentation_api.rb +2 -2
- data/lib/weft/generated/api/fetch_api.rb +6 -6
- data/lib/weft/generated/api/payments_api.rb +4 -2
- data/lib/weft/generated/api/purchases_api.rb +4 -4
- data/lib/weft/generated/api/resources_api.rb +2 -2
- data/lib/weft/generated/api/search_api.rb +4 -4
- data/lib/weft/generated/api/webhooks_api.rb +388 -0
- data/lib/weft/generated/api_client.rb +2 -2
- data/lib/weft/generated/api_error.rb +2 -2
- data/lib/weft/generated/api_model_base.rb +2 -2
- data/lib/weft/generated/configuration.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_approval.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_created.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_created_approval.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_created_response.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_request.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_status.rb +2 -2
- data/lib/weft/generated/models/account_bootstrap_status_response.rb +2 -2
- data/lib/weft/generated/models/account_details.rb +2 -2
- data/lib/weft/generated/models/api_key.rb +2 -2
- data/lib/weft/generated/models/api_key_created.rb +2 -2
- data/lib/weft/generated/models/api_key_created_response.rb +2 -2
- data/lib/weft/generated/models/api_key_list_response.rb +2 -2
- data/lib/weft/generated/models/auth_response.rb +2 -2
- data/lib/weft/generated/models/auth_response_data.rb +2 -2
- data/lib/weft/generated/models/balance_response.rb +2 -2
- data/lib/weft/generated/models/confirm_request.rb +2 -2
- data/lib/weft/generated/models/create_api_key_request.rb +2 -2
- data/lib/weft/generated/models/enrolled_resource.rb +2 -2
- data/lib/weft/generated/models/error.rb +2 -2
- data/lib/weft/generated/models/error_response.rb +2 -2
- data/lib/weft/generated/models/fetch403_response.rb +2 -2
- data/lib/weft/generated/models/fetch_balance_snapshot.rb +2 -2
- data/lib/weft/generated/models/fetch_error_response.rb +5 -5
- data/lib/weft/generated/models/fetch_request.rb +46 -5
- data/lib/weft/generated/models/fetch_request_body.rb +2 -2
- data/lib/weft/generated/models/fetch_response.rb +36 -64
- data/lib/weft/generated/models/get_purchase_id_parameter.rb +104 -0
- data/lib/weft/generated/models/insufficient_scope_response.rb +2 -2
- data/lib/weft/generated/models/me_api_key.rb +2 -2
- data/lib/weft/generated/models/me_api_key_creator.rb +2 -2
- data/lib/weft/generated/models/me_response.rb +2 -2
- data/lib/weft/generated/models/me_response_data.rb +2 -2
- data/lib/weft/generated/models/message_response.rb +2 -2
- data/lib/weft/generated/models/message_response_data.rb +2 -2
- data/lib/weft/generated/models/pagination.rb +2 -2
- data/lib/weft/generated/models/password_reset_request.rb +2 -2
- data/lib/weft/generated/models/password_update_request.rb +2 -2
- data/lib/weft/generated/models/payment.rb +2 -2
- data/lib/weft/generated/models/payment_list_response.rb +2 -2
- data/lib/weft/generated/models/payment_response.rb +2 -2
- data/lib/weft/generated/models/principal_wallet.rb +2 -2
- data/lib/weft/generated/models/promo_balance.rb +2 -2
- data/lib/weft/generated/models/purchase.rb +75 -3
- data/lib/weft/generated/models/purchase_artifact.rb +2 -2
- data/lib/weft/generated/models/purchase_list_response.rb +2 -2
- data/lib/weft/generated/models/purchase_response.rb +2 -2
- data/lib/weft/generated/models/rate_limit_response.rb +2 -2
- data/lib/weft/generated/models/resend_confirmation_request.rb +2 -2
- data/lib/weft/generated/models/resource_enrollment_request.rb +2 -2
- data/lib/weft/generated/models/resource_enrollment_response.rb +2 -2
- data/lib/weft/generated/models/resource_stats.rb +2 -2
- data/lib/weft/generated/models/search_access_method.rb +2 -2
- data/lib/weft/generated/models/search_capability_ref.rb +2 -2
- data/lib/weft/generated/models/search_compact_access.rb +179 -0
- data/lib/weft/generated/models/search_compact_access_price.rb +176 -0
- data/lib/weft/generated/models/search_compact_next_call.rb +275 -0
- data/lib/weft/generated/models/search_compact_result.rb +389 -0
- data/lib/weft/generated/models/search_compact_result_attribution.rb +166 -0
- data/lib/weft/generated/models/search_compact_result_blocked_scopes_inner.rb +156 -0
- data/lib/weft/generated/models/search_compact_result_operation.rb +183 -0
- data/lib/weft/generated/models/search_compact_result_provider.rb +156 -0
- data/lib/weft/generated/models/search_curated_callability.rb +2 -2
- data/lib/weft/generated/models/search_curated_execution.rb +2 -2
- data/lib/weft/generated/models/search_curated_operation.rb +2 -2
- data/lib/weft/generated/models/search_curated_service.rb +2 -2
- data/lib/weft/generated/models/search_curated_source.rb +2 -2
- data/lib/weft/generated/models/search_endpoint_call.rb +4 -4
- data/lib/weft/generated/models/search_endpoint_call_input_schema.rb +103 -0
- data/lib/weft/generated/models/search_endpoint_hit.rb +25 -6
- data/lib/weft/generated/models/search_endpoint_price.rb +2 -2
- data/lib/weft/generated/models/search_error_response.rb +4 -4
- data/lib/weft/generated/models/search_execution_mode_filter.rb +2 -2
- data/lib/weft/generated/models/search_filter_spec.rb +2 -2
- data/lib/weft/generated/models/search_helper_docs.rb +175 -0
- data/lib/weft/generated/models/search_method_filter.rb +2 -2
- data/lib/weft/generated/models/search_payment_offer.rb +2 -2
- data/lib/weft/generated/models/search_price_atomic_filter.rb +2 -2
- data/lib/weft/generated/models/search_price_usd_filter.rb +2 -2
- data/lib/weft/generated/models/search_protocol_filter.rb +2 -2
- data/lib/weft/generated/models/search_provider_ref.rb +2 -2
- data/lib/weft/generated/models/search_request.rb +50 -6
- data/lib/weft/generated/models/search_resource_type_filter.rb +2 -2
- data/lib/weft/generated/models/search_response.rb +71 -8
- data/lib/weft/generated/models/search_response_warnings_inner.rb +2 -2
- data/lib/weft/generated/models/search_result.rb +2 -2
- data/lib/weft/generated/models/search_string_set_filter.rb +2 -2
- data/lib/weft/generated/models/search_weft_fetch_compatibility.rb +28 -6
- data/lib/weft/generated/models/sign_in_request.rb +2 -2
- data/lib/weft/generated/models/sign_up_request.rb +2 -2
- data/lib/weft/generated/models/spending_policy.rb +2 -2
- data/lib/weft/generated/models/user.rb +2 -2
- data/lib/weft/generated/models/user_principal.rb +2 -2
- data/lib/weft/generated/models/wallet.rb +2 -2
- data/lib/weft/generated/version.rb +3 -3
- data/lib/weft/sdk.rb +3 -1
- metadata +39 -4
data/lib/weft/facilitator/fee.rb
CHANGED
|
@@ -1,27 +1,35 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
require_relative 'client'
|
|
4
|
+
|
|
1
5
|
module Weft
|
|
2
6
|
module Facilitator
|
|
3
7
|
module Fee
|
|
4
|
-
|
|
8
|
+
DEFAULT_TTL_MS = 5 * 60 * 1000
|
|
5
9
|
|
|
6
10
|
@cache = nil
|
|
7
11
|
|
|
8
12
|
class << self
|
|
9
|
-
def get_fee_info(client: Client.new, ttl:
|
|
13
|
+
def get_fee_info(client: Client.new, ttl: DEFAULT_TTL_MS)
|
|
10
14
|
return @cache[:fee] if cache_valid?
|
|
11
15
|
|
|
12
16
|
supported = client.supported
|
|
13
|
-
fee = supported['fee']
|
|
17
|
+
fee = supported['fee'] || supported[:fee]
|
|
14
18
|
raise 'Fee information not found in /supported response' unless fee
|
|
15
19
|
|
|
16
20
|
validate_fee!(fee)
|
|
21
|
+
normalized = {
|
|
22
|
+
'amount' => fee['amount'] || fee[:amount],
|
|
23
|
+
'asset' => fee['asset'] || fee[:asset],
|
|
24
|
+
'network' => fee['network'] || fee[:network]
|
|
25
|
+
}
|
|
17
26
|
|
|
18
27
|
@cache = {
|
|
19
|
-
fee:
|
|
20
|
-
fetched_at:
|
|
28
|
+
fee: normalized,
|
|
29
|
+
fetched_at: now_ms,
|
|
21
30
|
ttl: ttl
|
|
22
31
|
}
|
|
23
|
-
|
|
24
|
-
fee
|
|
32
|
+
normalized
|
|
25
33
|
end
|
|
26
34
|
|
|
27
35
|
def invalidate_fee_cache
|
|
@@ -33,13 +41,20 @@ module Weft
|
|
|
33
41
|
def cache_valid?
|
|
34
42
|
return false unless @cache
|
|
35
43
|
|
|
36
|
-
|
|
44
|
+
now_ms - @cache[:fetched_at] < @cache[:ttl]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def now_ms
|
|
48
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
37
49
|
end
|
|
38
50
|
|
|
39
51
|
def validate_fee!(fee)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
amount = fee['amount'] || fee[:amount]
|
|
53
|
+
asset = fee['asset'] || fee[:asset]
|
|
54
|
+
network = fee['network'] || fee[:network]
|
|
55
|
+
raise 'Invalid fee structure: amount must be a string' unless amount.is_a?(String)
|
|
56
|
+
raise 'Invalid fee structure: asset must be a string' unless asset.is_a?(String)
|
|
57
|
+
raise 'Invalid fee structure: network must be a string' unless network.is_a?(String)
|
|
43
58
|
end
|
|
44
59
|
end
|
|
45
60
|
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../generated/version'
|
|
4
|
+
require_relative 'json_wire'
|
|
5
|
+
require_relative 'product'
|
|
6
|
+
|
|
7
|
+
module Weft
|
|
8
|
+
module Facilitator
|
|
9
|
+
WEFT_DECLARED_HEADER = 'X-Weft-Declared'
|
|
10
|
+
WEFT_API_KEY_HEADER = 'X-API-Key'
|
|
11
|
+
HEADER_SAFE = /\A[\x21-\x7e]+\z/
|
|
12
|
+
ADAPTER_NAME = 'rack'
|
|
13
|
+
|
|
14
|
+
module Handshake
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def build_auth_headers(adapter, api_key, declaration)
|
|
18
|
+
declaration = stringify_declaration(declaration)
|
|
19
|
+
key = resolve_api_key(api_key)
|
|
20
|
+
supported = {
|
|
21
|
+
'User-Agent' => "weft-sdk-#{adapter}/#{sdk_version}"
|
|
22
|
+
}
|
|
23
|
+
supported['Authorization'] = "Bearer #{key}" unless key.nil?
|
|
24
|
+
|
|
25
|
+
declared = declared_identity_value(declaration)
|
|
26
|
+
supported[WEFT_DECLARED_HEADER] = declared unless declared.nil?
|
|
27
|
+
|
|
28
|
+
headers = { 'supported' => supported }
|
|
29
|
+
unless key.nil?
|
|
30
|
+
headers['settle'] = { WEFT_API_KEY_HEADER => key }
|
|
31
|
+
headers['verify'] = { WEFT_API_KEY_HEADER => key }
|
|
32
|
+
end
|
|
33
|
+
headers
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def declared_identity_value(declaration)
|
|
37
|
+
declared = Product.sanitize_product_identity(declaration)
|
|
38
|
+
dimensions = Product.resolve_dimensions(declaration['dimensions'], Product.create_warn)
|
|
39
|
+
payload = {}
|
|
40
|
+
payload['name'] = declared['name'] if declared.key?('name')
|
|
41
|
+
payload['type'] = declared['type'] if declared.key?('type')
|
|
42
|
+
payload['tags'] = declared['tags'] if declared.key?('tags')
|
|
43
|
+
payload['icon_url'] = declared['iconUrl'] if declared.key?('iconUrl')
|
|
44
|
+
payload['dimensions'] = dimensions unless dimensions.nil?
|
|
45
|
+
return nil if payload.empty?
|
|
46
|
+
|
|
47
|
+
JsonWire.base64url_encode(JsonWire.generate(payload))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resolve_api_key(api_key)
|
|
51
|
+
return nil if api_key.nil?
|
|
52
|
+
unless api_key.is_a?(String)
|
|
53
|
+
warn "[weft] ignoring apiKey: expected a string, got #{js_type(api_key)}"
|
|
54
|
+
return nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
trimmed = api_key.strip
|
|
58
|
+
if trimmed.empty?
|
|
59
|
+
warn '[weft] ignoring empty apiKey'
|
|
60
|
+
return nil
|
|
61
|
+
end
|
|
62
|
+
unless HEADER_SAFE.match?(trimmed)
|
|
63
|
+
warn '[weft] ignoring apiKey: it contains whitespace or non-printable ' \
|
|
64
|
+
'characters that cannot travel in an HTTP header'
|
|
65
|
+
return nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
trimmed
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def stringify_declaration(declaration)
|
|
72
|
+
return {} unless declaration.is_a?(Hash)
|
|
73
|
+
|
|
74
|
+
declaration.each_with_object({}) do |(key, value), out|
|
|
75
|
+
out[key.to_s] = value
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def sdk_version
|
|
80
|
+
defined?(SDK) ? SDK::VERSION : VERSION
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def js_type(value)
|
|
84
|
+
case value
|
|
85
|
+
when Integer, Float then 'number'
|
|
86
|
+
when TrueClass, FalseClass then 'boolean'
|
|
87
|
+
else 'object'
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Weft
|
|
7
|
+
module Facilitator
|
|
8
|
+
# JSON.stringify and the two base64 forms @x402/core puts on the wire.
|
|
9
|
+
module JsonWire
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def generate(value)
|
|
13
|
+
return nil if circular?(value)
|
|
14
|
+
|
|
15
|
+
JSON.generate(sanitize(value))
|
|
16
|
+
rescue JSON::GeneratorError, JSON::NestingError
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def circular?(value, seen = {})
|
|
21
|
+
case value
|
|
22
|
+
when Hash, Array
|
|
23
|
+
return true if seen[value.object_id]
|
|
24
|
+
|
|
25
|
+
seen[value.object_id] = true
|
|
26
|
+
children = value.is_a?(Hash) ? value.values : value
|
|
27
|
+
children.any? { |item| circular?(item, seen) }
|
|
28
|
+
else
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def sanitize(value)
|
|
34
|
+
case value
|
|
35
|
+
when Hash
|
|
36
|
+
value.each_with_object({}) do |(key, item), out|
|
|
37
|
+
out[key.is_a?(Symbol) ? key.to_s : key] = sanitize(item)
|
|
38
|
+
end
|
|
39
|
+
when Array
|
|
40
|
+
value.map { |item| sanitize(item) }
|
|
41
|
+
when Float
|
|
42
|
+
value.finite? ? value : nil
|
|
43
|
+
else
|
|
44
|
+
value
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def base64_encode(text)
|
|
49
|
+
Base64.strict_encode64(text.b)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def base64_decode(text)
|
|
53
|
+
Base64.strict_decode64(text).force_encoding(Encoding::UTF_8)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def base64url_encode(text)
|
|
57
|
+
Base64.urlsafe_encode64(text.b, padding: false)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def base64url_decode(text)
|
|
61
|
+
padded = text.tr('-_', '+/')
|
|
62
|
+
padded += '=' * ((4 - (padded.length % 4)) % 4)
|
|
63
|
+
Base64.decode64(padded).force_encoding(Encoding::UTF_8)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def encode_json(value)
|
|
67
|
+
json = generate(value)
|
|
68
|
+
raise ArgumentError, 'value is not JSON' if json.nil?
|
|
69
|
+
|
|
70
|
+
base64_encode(json)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|