xytara 3.1.16 → 3.2.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 +120 -92
- package/RELEASE_NOTES.md +7 -3
- package/START_HERE.md +56 -224
- package/bin/xytara.js +21 -8
- package/client.js +79 -1
- package/lib/{delivery_receipt.js → delivery_receipt_verify.js} +14 -100
- package/package.json +25 -35
- package/scripts/verify_client.js +418 -0
- package/scripts/verify_release_candidate.js +146 -45
- package/.env.example +0 -173
- package/ADAPTER_START_HERE.md +0 -56
- package/BSV_TERANODE_PLATFORM_DISCONTINUITY_RUNBOOK.md +0 -126
- package/CARRIED_HANDOFF_DEMO.md +0 -60
- package/EXAMPLE_PATHS.md +0 -53
- package/FINAL_CONTRACT.md +0 -498
- package/PARTNER_READY_PATH.md +0 -71
- package/PUBLIC_DEMO_SCRIPT.md +0 -78
- package/REAL_PAYMENT_SETUP.md +0 -320
- package/SERVICE_CONTRACT.md +0 -419
- package/SUPABASE_RUNTIME_STATE_SETUP.md +0 -61
- package/TERMINOLOGY.md +0 -50
- package/WHY_XYTARA_XOONYA.md +0 -63
- package/XT1_EXECUTION_TRUTH_STANDARD.md +0 -78
- package/XYTARA_ADAPTER_PROTOCOL_TRUTH_MODEL.md +0 -75
- package/XYTARA_AUTONOMOUS_ENTRY_MODEL.md +0 -124
- package/XYTARA_DEFAULT_PATH_MODEL.md +0 -84
- package/XYTARA_EXECUTION_TRUTH_MODEL.md +0 -171
- package/XYTARA_PAYMENT_RAIL_TRUTH_MODEL.md +0 -68
- package/adapters/AUTHORING_GUIDE.md +0 -244
- package/adapters/ONBOARDING_POSTURE.md +0 -61
- package/adapters/THIRD_PARTY_SUBMISSION_PROCESS.md +0 -84
- package/adapters/adapter-manifest.schema.json +0 -283
- package/adapters/examples/example-execution-adapter.js +0 -61
- package/adapters/examples/example-execution-adapter.manifest.json +0 -81
- package/adapters/examples/example-settlement-adapter.js +0 -55
- package/adapters/examples/example-settlement-adapter.manifest.json +0 -78
- package/adapters/examples/example-third-party-acp-registration.submission-bundle.json +0 -124
- package/adapters/examples/example-third-party-erc8004-registration.submission-bundle.json +0 -121
- package/adapters/examples/example-third-party-identity-registration.certification-pack.json +0 -22
- package/adapters/examples/example-third-party-identity-registration.record.json +0 -26
- package/adapters/examples/example-third-party-identity-registration.submission-bundle.json +0 -126
- package/adapters/examples/example-third-party-langchain-registration.submission-bundle.json +0 -124
- package/adapters/examples/example-third-party-mpp-registration.submission-bundle.json +0 -120
- package/adapters/examples/example-third-party-registration.certification-pack.json +0 -22
- package/adapters/examples/example-third-party-registration.record.json +0 -28
- package/adapters/examples/example-third-party-registration.submission-bundle.json +0 -126
- package/adapters/examples/example-third-party-settlement-registration.certification-pack.json +0 -22
- package/adapters/examples/example-third-party-settlement-registration.record.json +0 -26
- package/adapters/examples/example-third-party-settlement-registration.submission-bundle.json +0 -127
- package/adapters/examples/langchain-reference-execution-adapter.js +0 -81
- package/adapters/examples/langchain-reference-execution-adapter.manifest.json +0 -79
- package/adapters/examples/langgraph-reference-execution-adapter.js +0 -81
- package/adapters/examples/langgraph-reference-execution-adapter.manifest.json +0 -79
- package/adapters/examples/minimal-third-party-execution-adapter.js +0 -61
- package/adapters/examples/minimal-third-party-execution-adapter.manifest.json +0 -79
- package/adapters/examples/minimal-third-party-execution-registration.record.json +0 -26
- package/adapters/examples/minimal-third-party-execution.certification-pack.json +0 -22
- package/adapters/examples/minimal-third-party-execution.submission-bundle.json +0 -126
- package/adapters/integration-certification-pack.schema.json +0 -82
- package/adapters/integration-registration-record.schema.json +0 -114
- package/adapters/integration-submission-bundle-set.schema.json +0 -39
- package/adapters/integration-submission-bundle.schema.json +0 -34
- package/adapters/interfaces.js +0 -56
- package/bin/xytara-release.js +0 -1429
- package/examples/_demo_env.js +0 -40
- package/examples/adapter_review_walkthrough.js +0 -54
- package/examples/export_carried_handoff.js +0 -81
- package/examples/funded_runtime_walkthrough.js +0 -71
- package/examples/partner_launch_walkthrough.js +0 -44
- package/examples/quickstart.js +0 -3256
- package/fixtures/catalog.js +0 -1156
- package/index.js +0 -395
- package/integrations/dispatch.js +0 -276
- package/integrations/registry-snapshot.schema.json +0 -36
- package/integrations/registry.js +0 -2261
- package/integrations/views.js +0 -28
- package/lib/a2a_lane_contract.js +0 -104
- package/lib/a2a_rpc.js +0 -287
- package/lib/a2c_lane_contract.js +0 -111
- package/lib/account_auth.js +0 -585
- package/lib/acp_lane_contract.js +0 -54
- package/lib/activity_audit_contract.js +0 -322
- package/lib/adapter_certification_contract.js +0 -130
- package/lib/adapter_depth_contract.js +0 -218
- package/lib/adapter_pack.js +0 -118
- package/lib/adapter_partner_pack.js +0 -89
- package/lib/adapter_promotion_pack.js +0 -89
- package/lib/adapter_protocol_truth_contract.js +0 -229
- package/lib/agent_identity.js +0 -162
- package/lib/announcement_pack.js +0 -61
- package/lib/artifact_distribution_lane_contract.js +0 -54
- package/lib/asyncapi_contract.js +0 -150
- package/lib/auth_interop_contract.js +0 -80
- package/lib/authority_binding_lifecycle_contract.js +0 -182
- package/lib/autonomous_entry_contract.js +0 -409
- package/lib/bolt_adapter.js +0 -187
- package/lib/bolt_lane_contract.js +0 -55
- package/lib/bolt_payment_front.js +0 -224
- package/lib/business_cockpit.js +0 -378
- package/lib/buyer_event_log.js +0 -230
- package/lib/buyer_safety_policy.js +0 -132
- package/lib/capability_execution_truth.js +0 -276
- package/lib/capability_registry.js +0 -633
- package/lib/catalog_contract.js +0 -966
- package/lib/catalog_family_model.js +0 -193
- package/lib/catalog_views.js +0 -55
- package/lib/cdp_jwt.js +0 -57
- package/lib/checkout_event_security.js +0 -142
- package/lib/checkout_processor_adapter.js +0 -217
- package/lib/cloudevents_contract.js +0 -80
- package/lib/command_flow.js +0 -911
- package/lib/commerce_artifacts.js +0 -591
- package/lib/commerce_authority.js +0 -449
- package/lib/commerce_bridge.js +0 -274
- package/lib/commerce_cases.js +0 -399
- package/lib/commerce_checkout.js +0 -509
- package/lib/commerce_coordination.js +0 -346
- package/lib/commerce_economics.js +0 -4017
- package/lib/commerce_identity.js +0 -578
- package/lib/commerce_quotes.js +0 -266
- package/lib/commerce_reports.js +0 -14461
- package/lib/commerce_runtime.js +0 -322
- package/lib/commerce_shell.js +0 -257
- package/lib/crypto_agility_matrix.js +0 -125
- package/lib/default_path_contract.js +0 -412
- package/lib/delivery_summary_contract.js +0 -95
- package/lib/ecosystem_entry.js +0 -64
- package/lib/erc8004_lane_contract.js +0 -65
- package/lib/event_system_lane_contract.js +0 -75
- package/lib/execution_dedupe.js +0 -86
- package/lib/execution_truth_contract.js +0 -234
- package/lib/external_credit_bridge.js +0 -142
- package/lib/external_execution_policy.js +0 -143
- package/lib/external_execution_runtime.js +0 -238
- package/lib/feature_control_lane_contract.js +0 -54
- package/lib/first_run_conversion_contract.js +0 -290
- package/lib/framework_lane_contract.js +0 -89
- package/lib/framework_provider_promotion.js +0 -235
- package/lib/full_catalog_contract.js +0 -525
- package/lib/go_live_operator_pack.js +0 -391
- package/lib/http_transport.js +0 -99
- package/lib/identity_auth.js +0 -175
- package/lib/identity_interop_contract.js +0 -82
- package/lib/integration_matrix_contract.js +0 -102
- package/lib/l402_adapter.js +0 -241
- package/lib/l402_lane_contract.js +0 -55
- package/lib/l402_payment_front.js +0 -265
- package/lib/launch_narrative.js +0 -53
- package/lib/lifecycle_continuity_contract.js +0 -115
- package/lib/machine_identity_registry_contract.js +0 -199
- package/lib/major_rails_lane_contract.js +0 -150
- package/lib/market_lane_contract.js +0 -467
- package/lib/market_lane_depth_contract.js +0 -182
- package/lib/market_lane_promotion_contract.js +0 -210
- package/lib/market_lane_trace_contract.js +0 -278
- package/lib/mcp_lane_contract.js +0 -137
- package/lib/mpp_adapter.js +0 -237
- package/lib/network_transport.js +0 -110
- package/lib/offline_verifiability_recovery_contract.js +0 -155
- package/lib/openapi_contract.js +0 -300
- package/lib/operational_receipt_contract.js +0 -165
- package/lib/operator_intelligence.js +0 -407
- package/lib/outreach_copy_pack.js +0 -51
- package/lib/outreach_message_pack.js +0 -71
- package/lib/outreach_proof.js +0 -71
- package/lib/outreach_target_pack.js +0 -60
- package/lib/partner_intelligence.js +0 -105
- package/lib/payment_config.js +0 -257
- package/lib/payment_front_registry.js +0 -53
- package/lib/payment_protocol_contract.js +0 -165
- package/lib/payment_rail_truth_contract.js +0 -324
- package/lib/payment_verification.js +0 -357
- package/lib/phase_10_closeout_pack.js +0 -45
- package/lib/phase_10_completion_pack.js +0 -76
- package/lib/phase_10_decision_record_pack.js +0 -54
- package/lib/phase_10_decision_resolution_pack.js +0 -53
- package/lib/phase_10_demand_signal_adapters_runtime_pack.js +0 -74
- package/lib/phase_10_ecosystem_backlog_triage_runtime_pack.js +0 -74
- package/lib/phase_10_freeze_baseline_pack.js +0 -67
- package/lib/phase_10_freeze_review_pack.js +0 -64
- package/lib/phase_10_gate_pack.js +0 -57
- package/lib/phase_10_long_tail_continuity_pack.js +0 -80
- package/lib/phase_10_long_tail_ecosystem_pack.js +0 -66
- package/lib/phase_10_niche_extension_registry_runtime_pack.js +0 -74
- package/lib/phase_1_claude_mcp_pack.js +0 -60
- package/lib/phase_1_claude_mcp_runtime_pack.js +0 -52
- package/lib/phase_1_ecosystem_pack.js +0 -67
- package/lib/phase_1_openai_codex_pack.js +0 -60
- package/lib/phase_1_openai_codex_runtime_pack.js +0 -52
- package/lib/phase_2_base_runtime_pack.js +0 -71
- package/lib/phase_2_base_usdc_runtime_pack.js +0 -72
- package/lib/phase_2_closeout_pack.js +0 -65
- package/lib/phase_2_completion_pack.js +0 -113
- package/lib/phase_2_decision_record_pack.js +0 -66
- package/lib/phase_2_decision_resolution_pack.js +0 -69
- package/lib/phase_2_eth_runtime_pack.js +0 -70
- package/lib/phase_2_evm_base_runtime_pack.js +0 -73
- package/lib/phase_2_evm_runtime_pack.js +0 -71
- package/lib/phase_2_flip_preview_pack.js +0 -60
- package/lib/phase_2_freeze_review_pack.js +0 -99
- package/lib/phase_2_gate_pack.js +0 -77
- package/lib/phase_2_payment_rails_pack.js +0 -71
- package/lib/phase_2_usdc_runtime_pack.js +0 -71
- package/lib/phase_3_brc_runtime_pack.js +0 -81
- package/lib/phase_3_bsv_teranode_runtime_pack.js +0 -83
- package/lib/phase_3_closeout_pack.js +0 -62
- package/lib/phase_3_completion_pack.js +0 -94
- package/lib/phase_3_decision_record_pack.js +0 -64
- package/lib/phase_3_decision_resolution_pack.js +0 -69
- package/lib/phase_3_freeze_baseline_pack.js +0 -67
- package/lib/phase_3_freeze_review_pack.js +0 -80
- package/lib/phase_3_gate_pack.js +0 -76
- package/lib/phase_3_metanet_runtime_pack.js +0 -81
- package/lib/phase_3_native_bsv_pack.js +0 -91
- package/lib/phase_3_native_continuity_pack.js +0 -82
- package/lib/phase_4_attestation_runtime_pack.js +0 -75
- package/lib/phase_4_closeout_pack.js +0 -45
- package/lib/phase_4_completion_pack.js +0 -94
- package/lib/phase_4_decision_record_pack.js +0 -54
- package/lib/phase_4_decision_resolution_pack.js +0 -45
- package/lib/phase_4_erc8004_runtime_pack.js +0 -76
- package/lib/phase_4_freeze_baseline_pack.js +0 -67
- package/lib/phase_4_freeze_review_pack.js +0 -68
- package/lib/phase_4_gate_pack.js +0 -58
- package/lib/phase_4_identity_registry_runtime_pack.js +0 -75
- package/lib/phase_4_identity_trust_pack.js +0 -73
- package/lib/phase_4_trust_continuity_pack.js +0 -86
- package/lib/phase_5_antelope_runtime_pack.js +0 -76
- package/lib/phase_5_closeout_pack.js +0 -44
- package/lib/phase_5_completion_pack.js +0 -82
- package/lib/phase_5_constellation_dag_runtime_pack.js +0 -76
- package/lib/phase_5_decision_record_pack.js +0 -54
- package/lib/phase_5_decision_resolution_pack.js +0 -45
- package/lib/phase_5_digibyte_dgb_runtime_pack.js +0 -76
- package/lib/phase_5_freeze_baseline_pack.js +0 -67
- package/lib/phase_5_freeze_review_pack.js +0 -68
- package/lib/phase_5_gate_pack.js +0 -58
- package/lib/phase_5_hedera_hbar_runtime_pack.js +0 -76
- package/lib/phase_5_kaspa_kas_runtime_pack.js +0 -76
- package/lib/phase_5_major_rails_continuity_pack.js +0 -86
- package/lib/phase_5_major_rails_pack.js +0 -110
- package/lib/phase_5_metal_runtime_pack.js +0 -76
- package/lib/phase_5_polkadot_dot_runtime_pack.js +0 -76
- package/lib/phase_5_proton_xpr_runtime_pack.js +0 -76
- package/lib/phase_5_solana_runtime_pack.js +0 -76
- package/lib/phase_6_autogen_runtime_pack.js +0 -72
- package/lib/phase_6_closeout_pack.js +0 -46
- package/lib/phase_6_completion_pack.js +0 -77
- package/lib/phase_6_decision_record_pack.js +0 -54
- package/lib/phase_6_decision_resolution_pack.js +0 -53
- package/lib/phase_6_framework_continuity_pack.js +0 -81
- package/lib/phase_6_framework_runtime_pack.js +0 -68
- package/lib/phase_6_freeze_baseline_pack.js +0 -68
- package/lib/phase_6_freeze_review_pack.js +0 -65
- package/lib/phase_6_gate_pack.js +0 -59
- package/lib/phase_6_langchain_runtime_pack.js +0 -72
- package/lib/phase_6_langgraph_runtime_pack.js +0 -72
- package/lib/phase_6_semantic_kernel_runtime_pack.js +0 -72
- package/lib/phase_7_closeout_pack.js +0 -45
- package/lib/phase_7_completion_pack.js +0 -85
- package/lib/phase_7_decision_record_pack.js +0 -53
- package/lib/phase_7_decision_resolution_pack.js +0 -53
- package/lib/phase_7_event_system_continuity_pack.js +0 -89
- package/lib/phase_7_event_system_pack.js +0 -76
- package/lib/phase_7_freeze_baseline_pack.js +0 -74
- package/lib/phase_7_freeze_review_pack.js +0 -65
- package/lib/phase_7_gate_pack.js +0 -58
- package/lib/phase_7_kafka_runtime_pack.js +0 -74
- package/lib/phase_7_mqtt_runtime_pack.js +0 -74
- package/lib/phase_7_nats_runtime_pack.js +0 -74
- package/lib/phase_7_webhook_event_bus_runtime_pack.js +0 -74
- package/lib/phase_8_closeout_pack.js +0 -46
- package/lib/phase_8_completion_pack.js +0 -82
- package/lib/phase_8_decision_record_pack.js +0 -54
- package/lib/phase_8_decision_resolution_pack.js +0 -53
- package/lib/phase_8_external_receipt_import_runtime_pack.js +0 -74
- package/lib/phase_8_external_result_import_runtime_pack.js +0 -74
- package/lib/phase_8_freeze_baseline_pack.js +0 -71
- package/lib/phase_8_freeze_review_pack.js +0 -64
- package/lib/phase_8_gate_pack.js +0 -58
- package/lib/phase_8_proof_bridge_continuity_pack.js +0 -86
- package/lib/phase_8_proof_bridges_pack.js +0 -72
- package/lib/phase_8_proof_bundle_normalization_runtime_pack.js +0 -74
- package/lib/phase_9_closeout_pack.js +0 -46
- package/lib/phase_9_completion_pack.js +0 -82
- package/lib/phase_9_custody_refs_runtime_pack.js +0 -74
- package/lib/phase_9_decision_record_pack.js +0 -54
- package/lib/phase_9_decision_resolution_pack.js +0 -53
- package/lib/phase_9_freeze_baseline_pack.js +0 -71
- package/lib/phase_9_freeze_review_pack.js +0 -64
- package/lib/phase_9_gate_pack.js +0 -58
- package/lib/phase_9_operator_accounting_bridges_runtime_pack.js +0 -74
- package/lib/phase_9_treasury_connectivity_pack.js +0 -72
- package/lib/phase_9_treasury_continuity_pack.js +0 -86
- package/lib/phase_9_treasury_destinations_runtime_pack.js +0 -74
- package/lib/phase_program_pack.js +0 -120
- package/lib/pricing_optimization_contract.js +0 -775
- package/lib/protocol_lane_contract.js +0 -117
- package/lib/provenance_lane_contract.js +0 -54
- package/lib/provider_lane_contract.js +0 -240
- package/lib/provider_network_contract.js +0 -149
- package/lib/provider_payout_execution.js +0 -155
- package/lib/provider_registry.js +0 -852
- package/lib/provider_runtime_journey_contract.js +0 -183
- package/lib/public_surface_policy_contract.js +0 -111
- package/lib/publish_plan.js +0 -51
- package/lib/rate_limiter.js +0 -81
- package/lib/record_queries.js +0 -48
- package/lib/release_candidate.js +0 -50
- package/lib/release_center.js +0 -1093
- package/lib/release_history.js +0 -205
- package/lib/release_manifest.js +0 -113
- package/lib/release_pack.js +0 -453
- package/lib/request_rate_limit.js +0 -144
- package/lib/resource_views.js +0 -31
- package/lib/revenue_launch_path_contract.js +0 -326
- package/lib/route_matchers.js +0 -34
- package/lib/route_params.js +0 -19
- package/lib/runtime_bridge.js +0 -124
- package/lib/runtime_operations_worker.js +0 -282
- package/lib/runtime_state_store.js +0 -495
- package/lib/settlement_bsv_live.js +0 -600
- package/lib/settlement_bsv_teranode.js +0 -117
- package/lib/settlement_lane_contract.js +0 -111
- package/lib/shared_signals_lane_contract.js +0 -54
- package/lib/signed_audit_provenance_contract.js +0 -83
- package/lib/soft_launch_pack.js +0 -78
- package/lib/stablecoin_lane_contract.js +0 -76
- package/lib/stripe_mpp_lane_contract.js +0 -96
- package/lib/stripe_mpp_payment_front.js +0 -258
- package/lib/telemetry_lane_contract.js +0 -54
- package/lib/treasury_destinations_contract.js +0 -764
- package/lib/treasury_egress_policy_contract.js +0 -91
- package/lib/treasury_lane_contract.js +0 -84
- package/lib/trust_portability_boundary_contract.js +0 -72
- package/lib/x402_facilitator.js +0 -198
- package/lib/x402_lane_contract.js +0 -136
- package/lib/x402_settlement_recovery.js +0 -175
- package/scripts/buyer_events_daily_report.js +0 -79
- package/scripts/registry_cli.js +0 -275
- package/scripts/state_backup_offsite.js +0 -196
- package/scripts/verify_a2a_rpc.js +0 -131
- package/scripts/verify_adapters.js +0 -554
- package/scripts/verify_agent_identity.js +0 -153
- package/scripts/verify_all.js +0 -4963
- package/scripts/verify_bolt_adapter.js +0 -128
- package/scripts/verify_buyer_event_log.js +0 -128
- package/scripts/verify_buyer_safety.js +0 -141
- package/scripts/verify_cdp_facilitator.js +0 -110
- package/scripts/verify_checkout_processor.js +0 -109
- package/scripts/verify_commerce_bridge.js +0 -177
- package/scripts/verify_control_plane_contracts.js +0 -34
- package/scripts/verify_control_plane_routes.js +0 -70
- package/scripts/verify_delivery_summary.js +0 -112
- package/scripts/verify_examples.js +0 -19
- package/scripts/verify_execution_dedupe.js +0 -189
- package/scripts/verify_execution_surfacing.js +0 -76
- package/scripts/verify_external_execution_retry.js +0 -140
- package/scripts/verify_final_activation.js +0 -191
- package/scripts/verify_first_run_conversions.js +0 -81
- package/scripts/verify_framework_provider_promotion.js +0 -152
- package/scripts/verify_full_catalog.js +0 -174
- package/scripts/verify_integrations.js +0 -620
- package/scripts/verify_l402_adapter.js +0 -86
- package/scripts/verify_lifecycle_continuity.js +0 -96
- package/scripts/verify_lifecycle_spend_binding.js +0 -88
- package/scripts/verify_market_lane_depth.js +0 -94
- package/scripts/verify_market_lane_promotion.js +0 -103
- package/scripts/verify_market_lane_traces.js +0 -98
- package/scripts/verify_market_lanes.js +0 -102
- package/scripts/verify_mpp_adapter.js +0 -128
- package/scripts/verify_operator_observability_boundary.js +0 -83
- package/scripts/verify_pricing_experiment_plan.js +0 -124
- package/scripts/verify_production_readiness.js +0 -268
- package/scripts/verify_provider_network.js +0 -819
- package/scripts/verify_provider_runtime_breadth.js +0 -109
- package/scripts/verify_provider_runtime_journeys.js +0 -111
- package/scripts/verify_rate_limiter.js +0 -52
- package/scripts/verify_refund_credit.js +0 -106
- package/scripts/verify_revenue_launch_paths.js +0 -105
- package/scripts/verify_runtime_durability.js +0 -52
- package/scripts/verify_runtime_state_guard.js +0 -117
- package/scripts/verify_service.js +0 -15421
- package/scripts/verify_settlement.js +0 -116
- package/scripts/verify_tooling.js +0 -1412
- package/scripts/verify_treasury_public_boundary.js +0 -97
- package/scripts/verify_verify_execute_settle.js +0 -209
- package/scripts/verify_x402_facilitator.js +0 -307
- package/scripts/verify_x402_settlement_recovery.js +0 -153
- package/server.js +0 -12245
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// Verifies the generic external-commerce bridge (/v1/commerce/*): an upstream fiat front
|
|
4
|
-
// mints internal units for a confirmed purchase, then prepares a delegated-spend
|
|
5
|
-
// credential for the paying customer's agent. Covers: bearer fail-closed/forbidden,
|
|
6
|
-
// grants mint the mapped units + are idempotent per event (no double-mint on retry),
|
|
7
|
-
// unknown package -> 422, prepare-execution authorizes + issues a credential when funded
|
|
8
|
-
// and refuses when under-funded, and state reports the balance.
|
|
9
|
-
|
|
10
|
-
const assert = require("assert");
|
|
11
|
-
const http = require("http");
|
|
12
|
-
|
|
13
|
-
async function req(baseUrl, method, path, body, headers = {}) {
|
|
14
|
-
const res = await fetch(`${baseUrl}${path}`, {
|
|
15
|
-
method,
|
|
16
|
-
headers: { "content-type": "application/json", ...headers },
|
|
17
|
-
...(body !== undefined ? { body: JSON.stringify(body) } : {})
|
|
18
|
-
});
|
|
19
|
-
let json = null;
|
|
20
|
-
try { json = await res.json(); } catch (_) { json = null; }
|
|
21
|
-
return { status: res.status, json };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async function main() {
|
|
25
|
-
const prev = {
|
|
26
|
-
token: process.env.XYTARA_COMMERCE_BRIDGE_BEARER_TOKEN,
|
|
27
|
-
packMap: process.env.XYTARA_COMMERCE_PACK_MAP_JSON
|
|
28
|
-
};
|
|
29
|
-
const TOKEN = "test-commerce-bridge-token";
|
|
30
|
-
process.env.XYTARA_COMMERCE_BRIDGE_BEARER_TOKEN = TOKEN;
|
|
31
|
-
process.env.XYTARA_COMMERCE_PACK_MAP_JSON = JSON.stringify({ pkg_starter: 100, pkg_pro: 500 });
|
|
32
|
-
const auth = { authorization: `Bearer ${TOKEN}` };
|
|
33
|
-
|
|
34
|
-
delete require.cache[require.resolve("../server")];
|
|
35
|
-
const { createServer } = require("../server");
|
|
36
|
-
const server = createServer();
|
|
37
|
-
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
38
|
-
const baseUrl = `http://127.0.0.1:${server.address().port}`;
|
|
39
|
-
const ACCOUNT = "acct_commerce_test";
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
// 1. Auth mandatory: no bearer / wrong bearer -> 403.
|
|
43
|
-
let r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_starter", eventRef: "evt_1" });
|
|
44
|
-
assert.strictEqual(r.status, 403, "grants without bearer must 403");
|
|
45
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_starter", eventRef: "evt_1" }, { authorization: "Bearer wrong" });
|
|
46
|
-
assert.strictEqual(r.status, 403, "grants with wrong bearer must 403");
|
|
47
|
-
|
|
48
|
-
// 2. Grant mints the mapped units; response carries the upstream-read fields.
|
|
49
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_starter", purchaseRef: "ord_1", providerRef: "txn_1", eventRef: "evt_1", orderType: "one_time", metadata: { checkoutSurface: "public_checkout" } }, auth);
|
|
50
|
-
assert.strictEqual(r.status, 200, "grant must 200");
|
|
51
|
-
assert.strictEqual(r.json.ok, true, "grant ok");
|
|
52
|
-
assert.strictEqual(r.json.units, 100, "mapped units minted");
|
|
53
|
-
assert.ok(typeof r.json.grantId === "string" && r.json.grantId.length > 0, "grantId returned");
|
|
54
|
-
assert.strictEqual(r.json.hiddenAccountRef, ACCOUNT, "hiddenAccountRef echoed");
|
|
55
|
-
|
|
56
|
-
// 3. State reflects the balance.
|
|
57
|
-
r = await req(baseUrl, "GET", `/v1/commerce/state?accountRef=${ACCOUNT}`, undefined, auth);
|
|
58
|
-
assert.strictEqual(r.status, 200, "state 200");
|
|
59
|
-
assert.strictEqual(r.json.availableUnits, 100, "balance = 100 after grant");
|
|
60
|
-
|
|
61
|
-
// 4. Idempotent per event: a webhook retry (same eventRef) must NOT double-mint.
|
|
62
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_starter", purchaseRef: "ord_1", providerRef: "txn_1", eventRef: "evt_1" }, auth);
|
|
63
|
-
assert.strictEqual(r.status, 200, "replayed grant still 200");
|
|
64
|
-
const afterReplay = (await req(baseUrl, "GET", `/v1/commerce/state?accountRef=${ACCOUNT}`, undefined, auth)).json.availableUnits;
|
|
65
|
-
assert.strictEqual(afterReplay, 100, "replay must not double-mint (still 100)");
|
|
66
|
-
|
|
67
|
-
// 5. Unknown package -> 422.
|
|
68
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_does_not_exist", eventRef: "evt_2" }, auth);
|
|
69
|
-
assert.strictEqual(r.status, 422, "unknown package must 422");
|
|
70
|
-
assert.strictEqual(r.json.reason, "unknown_package", "422 reason");
|
|
71
|
-
|
|
72
|
-
// 6. prepare-execution authorizes + issues a BOUND delegated-spend credential.
|
|
73
|
-
r = await req(baseUrl, "POST", "/v1/commerce/prepare-execution", { accountRef: ACCOUNT, featureRef: "doc.analyze", quotedUnits: 40 }, auth);
|
|
74
|
-
assert.strictEqual(r.status, 200, "prepare 200");
|
|
75
|
-
assert.strictEqual(r.json.authorized, true, "authorized when funded");
|
|
76
|
-
assert.ok(typeof r.json.spendAuthorityRef === "string" && r.json.spendAuthorityRef.length > 0, "spendAuthorityRef (binding) issued");
|
|
77
|
-
assert.ok(typeof r.json.spendAuthorityToken === "string" && r.json.spendAuthorityToken.length > 0, "agent-presentable token issued");
|
|
78
|
-
assert.strictEqual(r.json.boundUnits, 40, "credential is BOUND to the quote (not the whole balance)");
|
|
79
|
-
assert.ok(typeof r.json.validUntil === "string", "validUntil set");
|
|
80
|
-
assert.ok(Array.isArray(r.json.capabilitySummary) && r.json.capabilitySummary.includes("doc.analyze"), "capability summarized");
|
|
81
|
-
|
|
82
|
-
// 6b. A positive quote is required (an unbounded authorization is never issued).
|
|
83
|
-
r = await req(baseUrl, "POST", "/v1/commerce/prepare-execution", { accountRef: ACCOUNT, featureRef: "doc.analyze" }, auth);
|
|
84
|
-
assert.strictEqual(r.json.authorized, false, "no quote -> not authorized");
|
|
85
|
-
assert.strictEqual(r.json.authorityDecision, "quoted_units_required", "quote-required decision");
|
|
86
|
-
|
|
87
|
-
// 6c. A malformed agent key REFUSES rather than silently downgrading to bearer-only.
|
|
88
|
-
r = await req(baseUrl, "POST", "/v1/commerce/prepare-execution", { accountRef: ACCOUNT, featureRef: "doc.analyze", quotedUnits: 10, delegatedSpend: { agent_public_key: "not-a-real-key" } }, auth);
|
|
89
|
-
assert.strictEqual(r.json.authorized, false, "invalid agent key -> refuse");
|
|
90
|
-
assert.strictEqual(r.json.authorityDecision, "invalid_agent_key", "invalid_agent_key decision");
|
|
91
|
-
|
|
92
|
-
// 7. prepare-execution refuses when the quote exceeds the balance.
|
|
93
|
-
r = await req(baseUrl, "POST", "/v1/commerce/prepare-execution", { accountRef: ACCOUNT, featureRef: "doc.analyze", quotedUnits: 999999 }, auth);
|
|
94
|
-
assert.strictEqual(r.status, 200, "under-funded prepare still 200 (soft decision)");
|
|
95
|
-
assert.strictEqual(r.json.authorized, false, "not authorized when under-funded");
|
|
96
|
-
assert.strictEqual(r.json.authorityDecision, "insufficient_units", "decision surfaced");
|
|
97
|
-
assert.strictEqual(r.json.spendAuthorityRef, null, "no credential issued when refused");
|
|
98
|
-
|
|
99
|
-
// 8. account_ref required.
|
|
100
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { packageRef: "pkg_starter", eventRef: "evt_3" }, auth);
|
|
101
|
-
assert.strictEqual(r.status, 400, "missing accountRef must 400");
|
|
102
|
-
assert.strictEqual(r.json.reason, "account_ref_required", "400 reason");
|
|
103
|
-
|
|
104
|
-
// 8b. A SHARED eventRef across two accounts must NOT collide (each account minted).
|
|
105
|
-
const ACCOUNT_B = "acct_commerce_test_B";
|
|
106
|
-
await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_pro", eventRef: "shared_evt" }, auth);
|
|
107
|
-
await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT_B, packageRef: "pkg_pro", eventRef: "shared_evt" }, auth);
|
|
108
|
-
const balB = (await req(baseUrl, "GET", `/v1/commerce/state?accountRef=${ACCOUNT_B}`, undefined, auth)).json.availableUnits;
|
|
109
|
-
assert.strictEqual(balB, 500, "account B minted its own units despite sharing eventRef with A (no grant_id collision)");
|
|
110
|
-
|
|
111
|
-
// 9. ENFORCEMENT: a credential bounded to a quote must actually be bounded at SPEND
|
|
112
|
-
// time on the consume route, and cannot target another account.
|
|
113
|
-
const prep = await req(baseUrl, "POST", "/v1/commerce/prepare-execution", { accountRef: ACCOUNT, featureRef: "doc.analyze", quotedUnits: 40 }, auth);
|
|
114
|
-
const spendToken = prep.json.spendAuthorityToken;
|
|
115
|
-
assert.ok(spendToken && spendToken.startsWith("xytara_spend_"), "prepare issued a delegated spend token");
|
|
116
|
-
const spendAuth = { authorization: `Bearer ${spendToken}` };
|
|
117
|
-
|
|
118
|
-
// 9a. Over-quota spend is REJECTED (the quote is enforced, not just echoed).
|
|
119
|
-
let sp = await req(baseUrl, "POST", "/v1/economics/rails/credits/consume", { account_id: ACCOUNT, units: 50, task_ref: "doc.analyze" }, spendAuth);
|
|
120
|
-
assert.strictEqual(sp.status, 403, "consuming > quoted units must be rejected (bound enforced on consume)");
|
|
121
|
-
assert.strictEqual(sp.json.reason, "authority_consequence_bound_exceeded", "bound-exceeded reason");
|
|
122
|
-
|
|
123
|
-
// 9b. Targeting ANOTHER account with this credential is REJECTED (account pinned).
|
|
124
|
-
sp = await req(baseUrl, "POST", "/v1/economics/rails/credits/consume", { account_id: ACCOUNT_B, units: 10, task_ref: "doc.analyze" }, spendAuth);
|
|
125
|
-
assert.strictEqual(sp.status, 403, "a credential for account A cannot spend account B");
|
|
126
|
-
assert.strictEqual(sp.json.reason, "delegated_account_mismatch", "account-mismatch reason");
|
|
127
|
-
|
|
128
|
-
// 9c. A within-quote spend on the OWN account SUCCEEDS.
|
|
129
|
-
sp = await req(baseUrl, "POST", "/v1/economics/rails/credits/consume", { account_id: ACCOUNT, units: 30, task_ref: "doc.analyze" }, spendAuth);
|
|
130
|
-
assert.strictEqual(sp.status, 200, `within-quote spend must succeed (got ${sp.status}: ${JSON.stringify(sp.json).slice(0,160)})`);
|
|
131
|
-
|
|
132
|
-
// 10. SETTLE: trusted server-side consumption via the commerce bearer (the upstream
|
|
133
|
-
// seam burns units after executing paid work; no delegated token involved).
|
|
134
|
-
const ACCOUNT_S = "acct_commerce_settle";
|
|
135
|
-
await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT_S, packageRef: "pkg_pro", eventRef: "evt_settle" }, auth); // +500
|
|
136
|
-
// 10a. Settle requires the commerce bearer.
|
|
137
|
-
r = await req(baseUrl, "POST", "/v1/commerce/settle", { accountRef: ACCOUNT_S, units: 10 });
|
|
138
|
-
assert.strictEqual(r.status, 403, "settle without bearer must 403");
|
|
139
|
-
// 10b. account_ref + a positive unit count are required.
|
|
140
|
-
r = await req(baseUrl, "POST", "/v1/commerce/settle", { units: 10 }, auth);
|
|
141
|
-
assert.strictEqual(r.status, 400, "settle without accountRef must 400");
|
|
142
|
-
assert.strictEqual(r.json.reason, "account_ref_required", "settle 400 reason");
|
|
143
|
-
r = await req(baseUrl, "POST", "/v1/commerce/settle", { accountRef: ACCOUNT_S, units: 0 }, auth);
|
|
144
|
-
assert.strictEqual(r.status, 400, "settle without positive units must 400");
|
|
145
|
-
assert.strictEqual(r.json.reason, "units_required", "settle units reason");
|
|
146
|
-
// 10c. Over-balance settle is refused (balance is the hard cap).
|
|
147
|
-
r = await req(baseUrl, "POST", "/v1/commerce/settle", { accountRef: ACCOUNT_S, units: 999999, taskRef: "doc.analyze" }, auth);
|
|
148
|
-
assert.strictEqual(r.status, 409, "over-balance settle must 409");
|
|
149
|
-
assert.strictEqual(r.json.reason, "insufficient_credits", "settle insufficient reason");
|
|
150
|
-
// 10d. Within-balance settle burns units and returns the credit_spend/usage_meter shape.
|
|
151
|
-
r = await req(baseUrl, "POST", "/v1/commerce/settle", { accountRef: ACCOUNT_S, units: 200, taskRef: "doc.analyze", transactionRef: "txn_settle_1" }, auth);
|
|
152
|
-
assert.strictEqual(r.status, 200, `within-balance settle must 200 (got ${r.status}: ${JSON.stringify(r.json).slice(0,160)})`);
|
|
153
|
-
assert.strictEqual(r.json.ok, true, "settle ok");
|
|
154
|
-
assert.ok(r.json.credit_spend && typeof r.json.credit_spend.credit_spend_id === "string", "settle returns credit_spend");
|
|
155
|
-
assert.ok(typeof r.json.credit_spend.usage_meter_id === "string", "settle returns usage_meter_id");
|
|
156
|
-
const afterSettle = (await req(baseUrl, "GET", `/v1/commerce/state?accountRef=${ACCOUNT_S}`, undefined, auth)).json.availableUnits;
|
|
157
|
-
assert.strictEqual(afterSettle, 300, "settle burned 200 of 500 (300 left)");
|
|
158
|
-
|
|
159
|
-
// 9. Fail-closed when the bridge token is unset.
|
|
160
|
-
delete process.env.XYTARA_COMMERCE_BRIDGE_BEARER_TOKEN;
|
|
161
|
-
r = await req(baseUrl, "POST", "/v1/commerce/grants", { accountRef: ACCOUNT, packageRef: "pkg_starter", eventRef: "evt_4" }, auth);
|
|
162
|
-
assert.strictEqual(r.status, 403, "unset token must fail closed (403)");
|
|
163
|
-
assert.strictEqual(r.json.reason, "commerce_bridge_auth_not_configured", "fail-closed reason");
|
|
164
|
-
|
|
165
|
-
console.log("xytara verify:commerce-bridge passed");
|
|
166
|
-
} finally {
|
|
167
|
-
await new Promise((resolve) => server.close(resolve));
|
|
168
|
-
const restore = (k, v) => { if (v === undefined) delete process.env[k]; else process.env[k] = v; };
|
|
169
|
-
restore("XYTARA_COMMERCE_BRIDGE_BEARER_TOKEN", prev.token);
|
|
170
|
-
restore("XYTARA_COMMERCE_PACK_MAP_JSON", prev.packMap);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
main().catch((error) => {
|
|
175
|
-
console.error(error && error.message ? error.message : error);
|
|
176
|
-
process.exitCode = 1;
|
|
177
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const {
|
|
5
|
-
summarizeAdapterCertificationContractPack,
|
|
6
|
-
summarizeTrustPortabilityBoundaryContractPack,
|
|
7
|
-
summarizeSignedAuditProvenanceContractPack
|
|
8
|
-
} = require("../index.js");
|
|
9
|
-
|
|
10
|
-
function main() {
|
|
11
|
-
const adapterCertification = summarizeAdapterCertificationContractPack();
|
|
12
|
-
const trustPortabilityBoundary = summarizeTrustPortabilityBoundaryContractPack();
|
|
13
|
-
const signedAuditProvenance = summarizeSignedAuditProvenanceContractPack();
|
|
14
|
-
|
|
15
|
-
assert.strictEqual(adapterCertification.ok, true, "adapter certification summary failed");
|
|
16
|
-
assert.strictEqual(adapterCertification.certification_state_count >= 5, true, "adapter certification state count mismatch");
|
|
17
|
-
assert.strictEqual(adapterCertification.certification_front_count >= 8, true, "adapter certification front count mismatch");
|
|
18
|
-
assert.strictEqual(adapterCertification.required_test_category_count >= 8, true, "adapter certification test category count mismatch");
|
|
19
|
-
|
|
20
|
-
assert.strictEqual(trustPortabilityBoundary.ok, true, "trust portability boundary summary failed");
|
|
21
|
-
assert.strictEqual(trustPortabilityBoundary.portable_axis_count >= 4, true, "trust portability axis count mismatch");
|
|
22
|
-
assert.strictEqual(trustPortabilityBoundary.non_claim_count >= 5, true, "trust portability non-claim count mismatch");
|
|
23
|
-
assert.strictEqual(trustPortabilityBoundary.evidence_requirement_count >= 5, true, "trust portability evidence requirement count mismatch");
|
|
24
|
-
|
|
25
|
-
assert.strictEqual(signedAuditProvenance.ok, true, "signed audit provenance summary failed");
|
|
26
|
-
assert.strictEqual(signedAuditProvenance.evidence_surface_count >= 6, true, "signed audit provenance surface count mismatch");
|
|
27
|
-
assert.strictEqual(signedAuditProvenance.required_field_count >= 7, true, "signed audit provenance required field count mismatch");
|
|
28
|
-
assert.strictEqual(signedAuditProvenance.export_rule_count >= 4, true, "signed audit provenance export rule count mismatch");
|
|
29
|
-
|
|
30
|
-
console.log("xytara verify:control-plane-contracts passed");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
main();
|
|
34
|
-
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const { createServer } = require("../server.js");
|
|
5
|
-
|
|
6
|
-
async function getJson(baseUrl, route) {
|
|
7
|
-
const response = await fetch(`${baseUrl}${route}`);
|
|
8
|
-
return {
|
|
9
|
-
status: response.status,
|
|
10
|
-
json: await response.json()
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function main() {
|
|
15
|
-
const server = createServer();
|
|
16
|
-
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
17
|
-
const address = server.address();
|
|
18
|
-
const baseUrl = `http://127.0.0.1:${address.port}`;
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const adapterCertification = await getJson(baseUrl, "/v1/adapter-certification");
|
|
22
|
-
assert.strictEqual(adapterCertification.status, 200, "adapter certification route failed");
|
|
23
|
-
assert.strictEqual(adapterCertification.json.category, "naxytra-adapter-certification-contract", "adapter certification category mismatch");
|
|
24
|
-
assert.strictEqual(adapterCertification.json.certification_fronts.length >= 8, true, "adapter certification front count mismatch");
|
|
25
|
-
|
|
26
|
-
const adapterCertificationSummary = await getJson(baseUrl, "/v1/adapter-certification/summary");
|
|
27
|
-
assert.strictEqual(adapterCertificationSummary.status, 200, "adapter certification summary route failed");
|
|
28
|
-
assert.strictEqual(adapterCertificationSummary.json.certification_state_count >= 5, true, "adapter certification summary count mismatch");
|
|
29
|
-
|
|
30
|
-
const adapterCertificationDetail = await getJson(baseUrl, "/v1/adapter-certification/protocol_front");
|
|
31
|
-
assert.strictEqual(adapterCertificationDetail.status, 200, "adapter certification detail route failed");
|
|
32
|
-
assert.strictEqual(adapterCertificationDetail.json.front.front_id, "protocol_front", "adapter certification detail mismatch");
|
|
33
|
-
|
|
34
|
-
const trustBoundary = await getJson(baseUrl, "/v1/trust-portability-boundary");
|
|
35
|
-
assert.strictEqual(trustBoundary.status, 200, "trust portability boundary route failed");
|
|
36
|
-
assert.strictEqual(trustBoundary.json.category, "naxytra-trust-portability-boundary-contract", "trust portability boundary category mismatch");
|
|
37
|
-
assert.strictEqual(trustBoundary.json.portable_axes.length >= 4, true, "trust portability boundary axis count mismatch");
|
|
38
|
-
|
|
39
|
-
const trustBoundarySummary = await getJson(baseUrl, "/v1/trust-portability-boundary/summary");
|
|
40
|
-
assert.strictEqual(trustBoundarySummary.status, 200, "trust portability boundary summary route failed");
|
|
41
|
-
assert.strictEqual(trustBoundarySummary.json.portable_axis_count >= 4, true, "trust portability boundary summary count mismatch");
|
|
42
|
-
|
|
43
|
-
const trustBoundaryDetail = await getJson(baseUrl, "/v1/trust-portability-boundary/agent_identity_portability");
|
|
44
|
-
assert.strictEqual(trustBoundaryDetail.status, 200, "trust portability boundary detail route failed");
|
|
45
|
-
assert.strictEqual(trustBoundaryDetail.json.axis.axis_id, "agent_identity_portability", "trust portability boundary detail mismatch");
|
|
46
|
-
|
|
47
|
-
const signedAudit = await getJson(baseUrl, "/v1/signed-audit-provenance");
|
|
48
|
-
assert.strictEqual(signedAudit.status, 200, "signed audit provenance route failed");
|
|
49
|
-
assert.strictEqual(signedAudit.json.category, "naxytra-signed-audit-provenance-contract", "signed audit provenance category mismatch");
|
|
50
|
-
assert.strictEqual(signedAudit.json.evidence_surfaces.length >= 6, true, "signed audit provenance evidence surface count mismatch");
|
|
51
|
-
|
|
52
|
-
const signedAuditSummary = await getJson(baseUrl, "/v1/signed-audit-provenance/summary");
|
|
53
|
-
assert.strictEqual(signedAuditSummary.status, 200, "signed audit provenance summary route failed");
|
|
54
|
-
assert.strictEqual(signedAuditSummary.json.evidence_surface_count >= 6, true, "signed audit provenance summary count mismatch");
|
|
55
|
-
|
|
56
|
-
const signedAuditDetail = await getJson(baseUrl, "/v1/signed-audit-provenance/release_provenance");
|
|
57
|
-
assert.strictEqual(signedAuditDetail.status, 200, "signed audit provenance detail route failed");
|
|
58
|
-
assert.strictEqual(signedAuditDetail.json.surface.surface_id, "release_provenance", "signed audit provenance detail mismatch");
|
|
59
|
-
} finally {
|
|
60
|
-
await new Promise((resolve) => server.close(resolve));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
console.log("xytara verify:control-plane-routes passed");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
main().catch((error) => {
|
|
67
|
-
console.error(error);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
});
|
|
70
|
-
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const { createServer } = require("../server");
|
|
5
|
-
const {
|
|
6
|
-
buildDeliverySummaryPack,
|
|
7
|
-
summarizeDeliveryState
|
|
8
|
-
} = require("../lib/delivery_summary_contract");
|
|
9
|
-
|
|
10
|
-
async function getJson(baseUrl, routePath) {
|
|
11
|
-
const response = await fetch(`${baseUrl}${routePath}`);
|
|
12
|
-
return {
|
|
13
|
-
status: response.status,
|
|
14
|
-
json: await response.json()
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async function main() {
|
|
19
|
-
const summary = summarizeDeliveryState({
|
|
20
|
-
deliveries: new Map([
|
|
21
|
-
[
|
|
22
|
-
"delivery_1",
|
|
23
|
-
{
|
|
24
|
-
delivery_id: "delivery_1",
|
|
25
|
-
status: "delivered",
|
|
26
|
-
callback_url: "https://agent.example/callbacks/demo",
|
|
27
|
-
callback_delivery: {
|
|
28
|
-
status: "delivered",
|
|
29
|
-
signature_mode: "hmac_sha256"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
[
|
|
34
|
-
"delivery_2",
|
|
35
|
-
{
|
|
36
|
-
delivery_id: "delivery_2",
|
|
37
|
-
status: "pending_delivery",
|
|
38
|
-
callback_url: null,
|
|
39
|
-
callback_delivery: null
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
|
-
[
|
|
43
|
-
"delivery_3",
|
|
44
|
-
{
|
|
45
|
-
delivery_id: "delivery_3",
|
|
46
|
-
status: "delivered",
|
|
47
|
-
callback_url: "https://agent.example/callbacks/retry",
|
|
48
|
-
callback_delivery: {
|
|
49
|
-
status: "retrying",
|
|
50
|
-
signature_mode: "hmac_sha256"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
])
|
|
55
|
-
});
|
|
56
|
-
const pack = buildDeliverySummaryPack({
|
|
57
|
-
deliveries: new Map([
|
|
58
|
-
[
|
|
59
|
-
"delivery_1",
|
|
60
|
-
{
|
|
61
|
-
delivery_id: "delivery_1",
|
|
62
|
-
status: "delivered",
|
|
63
|
-
callback_url: "https://agent.example/callbacks/demo",
|
|
64
|
-
callback_delivery: {
|
|
65
|
-
status: "delivered",
|
|
66
|
-
signature_mode: "hmac_sha256"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
])
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
assert.strictEqual(pack.ok, true, "delivery summary pack should be ok");
|
|
74
|
-
assert.strictEqual(summary.delivery_count, 3, "delivery count mismatch");
|
|
75
|
-
assert.strictEqual(summary.callback_delivery_count, 2, "callback delivery count mismatch");
|
|
76
|
-
assert.strictEqual(summary.delivered_delivery_count, 2, "delivered count mismatch");
|
|
77
|
-
assert.strictEqual(summary.retrying_callback_delivery_count, 1, "retrying callback count mismatch");
|
|
78
|
-
assert.strictEqual(summary.signed_callback_delivery_count, 2, "signed callback count mismatch");
|
|
79
|
-
|
|
80
|
-
const server = createServer();
|
|
81
|
-
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
82
|
-
const address = server.address();
|
|
83
|
-
const baseUrl = `http://127.0.0.1:${address.port}`;
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
const response = await getJson(baseUrl, "/v1/deliveries/summary");
|
|
87
|
-
assert.strictEqual(response.status, 200, "delivery summary route failed");
|
|
88
|
-
assert.strictEqual(response.json.ok, true, "delivery summary ok missing");
|
|
89
|
-
assert.strictEqual(response.json.delivery_count >= 0, true, "delivery summary count missing");
|
|
90
|
-
assert.strictEqual(typeof response.json.callback_delivery_enabled, "boolean", "delivery summary callback posture missing");
|
|
91
|
-
} finally {
|
|
92
|
-
await new Promise((resolve) => server.close(resolve));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
console.log(JSON.stringify({
|
|
96
|
-
ok: true,
|
|
97
|
-
product: "xytara",
|
|
98
|
-
category: "machine-commerce-delivery-summary-verification",
|
|
99
|
-
verification_version: "xytara-delivery-summary-verification-v1",
|
|
100
|
-
delivery_count: summary.delivery_count,
|
|
101
|
-
callback_delivery_count: summary.callback_delivery_count,
|
|
102
|
-
delivered_delivery_count: summary.delivered_delivery_count,
|
|
103
|
-
retrying_callback_delivery_count: summary.retrying_callback_delivery_count,
|
|
104
|
-
signed_callback_delivery_count: summary.signed_callback_delivery_count,
|
|
105
|
-
boundary: "callback_delivery_posture_should_be_publicly_inspectable_and_counted"
|
|
106
|
-
}, null, 2));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
main().catch((error) => {
|
|
110
|
-
console.error(error);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const { spawnSync } = require("child_process");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
|
|
6
|
-
function runExample(scriptPath) {
|
|
7
|
-
const result = spawnSync(process.execPath, [scriptPath], {
|
|
8
|
-
stdio: "inherit"
|
|
9
|
-
});
|
|
10
|
-
if (result.status !== 0) {
|
|
11
|
-
process.exit(result.status || 1);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
runExample(path.join(__dirname, "..", "examples", "quickstart.js"));
|
|
16
|
-
runExample(path.join(__dirname, "..", "examples", "export_carried_handoff.js"));
|
|
17
|
-
runExample(path.join(__dirname, "..", "examples", "partner_launch_walkthrough.js"));
|
|
18
|
-
runExample(path.join(__dirname, "..", "examples", "funded_runtime_walkthrough.js"));
|
|
19
|
-
runExample(path.join(__dirname, "..", "examples", "adapter_review_walkthrough.js"));
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// Verifies the deferred-x402 execution dedupe guard:
|
|
4
|
-
// - two CONCURRENT commands carrying the SAME signed authorization (same EIP-3009
|
|
5
|
-
// nonce) against a slow executor result in exactly ONE execution and ONE settle;
|
|
6
|
-
// the duplicate is rejected 409 payment_authorization_in_progress and not charged;
|
|
7
|
-
// - a later command with a DIFFERENT authorization is not blocked;
|
|
8
|
-
// - unit level: the guard is a no-op for non-deferred verifications, fails open when
|
|
9
|
-
// the store is missing, rejects an in-flight duplicate, frees the slot on release,
|
|
10
|
-
// and prunes entries past their TTL.
|
|
11
|
-
//
|
|
12
|
-
// No real network or chain is used.
|
|
13
|
-
|
|
14
|
-
const assert = require("assert");
|
|
15
|
-
const http = require("http");
|
|
16
|
-
const { claimDeferredExecution, releaseDeferredExecution, deferredAuthorizationKey } = require("../lib/execution_dedupe");
|
|
17
|
-
|
|
18
|
-
const ACCEPTS = [
|
|
19
|
-
{
|
|
20
|
-
scheme: "exact",
|
|
21
|
-
network: "eip155:84532",
|
|
22
|
-
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
23
|
-
amount: "1000",
|
|
24
|
-
payTo: "0x7cd2E0Ed2721319B20FAac4109774d030833F84D",
|
|
25
|
-
extra: { name: "USDC", version: "2" },
|
|
26
|
-
maxTimeoutSeconds: 60
|
|
27
|
-
}
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
function startMockServer() {
|
|
31
|
-
const calls = { verify: 0, settle: 0, execSlow: 0 };
|
|
32
|
-
const server = http.createServer((req, res) => {
|
|
33
|
-
const chunks = [];
|
|
34
|
-
req.on("data", (c) => chunks.push(c));
|
|
35
|
-
req.on("end", () => {
|
|
36
|
-
let body = {};
|
|
37
|
-
try { body = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}"); } catch (_) { body = {}; }
|
|
38
|
-
const reply = (payload, status) => {
|
|
39
|
-
const text = JSON.stringify(payload);
|
|
40
|
-
res.writeHead(status || 200, { "content-type": "application/json", "content-length": Buffer.byteLength(text) });
|
|
41
|
-
res.end(text);
|
|
42
|
-
};
|
|
43
|
-
if (req.method === "POST" && req.url === "/verify") { calls.verify += 1; return reply({ isValid: true, payer: "0x1111111111111111111111111111111111111111" }); }
|
|
44
|
-
if (req.method === "POST" && req.url === "/settle") { calls.settle += 1; return reply({ success: true, transaction: "0xmocktx", network: "eip155:84532", payer: "0x1111111111111111111111111111111111111111" }); }
|
|
45
|
-
if (req.method === "POST" && req.url === "/exec-slow") {
|
|
46
|
-
calls.execSlow += 1;
|
|
47
|
-
return setTimeout(() => reply({ ok: true, status: "completed", output: { value: "slow-ok" } }), 350);
|
|
48
|
-
}
|
|
49
|
-
if (req.method === "POST" && req.url === "/exec-fail") {
|
|
50
|
-
calls.execFail = (calls.execFail || 0) + 1;
|
|
51
|
-
return reply({ ok: false, reason: "data_required" }, 502);
|
|
52
|
-
}
|
|
53
|
-
res.writeHead(404); res.end();
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
return new Promise((resolve) => server.listen(0, "127.0.0.1", () => resolve({ server, calls, port: server.address().port })));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function paymentHeader(nonceHex) {
|
|
60
|
-
const accepted = ACCEPTS[0];
|
|
61
|
-
return Buffer.from(JSON.stringify({
|
|
62
|
-
x402Version: 2,
|
|
63
|
-
accepted,
|
|
64
|
-
payload: {
|
|
65
|
-
signature: "ok",
|
|
66
|
-
authorization: {
|
|
67
|
-
from: "0x1111111111111111111111111111111111111111",
|
|
68
|
-
to: accepted.payTo,
|
|
69
|
-
value: accepted.amount,
|
|
70
|
-
validAfter: "0",
|
|
71
|
-
validBefore: String(Math.floor(Date.now() / 1000) + 600),
|
|
72
|
-
nonce: nonceHex
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}), "utf8").toString("base64");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function post(baseUrl, path, body, headers = {}) {
|
|
79
|
-
const res = await fetch(`${baseUrl}${path}`, { method: "POST", headers: { "content-type": "application/json", ...headers }, body: JSON.stringify(body) });
|
|
80
|
-
let json = null;
|
|
81
|
-
try { json = await res.json(); } catch (_) { json = null; }
|
|
82
|
-
return { status: res.status, json, receipt: res.headers.get("payment-response") };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function runUnitChecks() {
|
|
86
|
-
// No-op for a non-deferred verification.
|
|
87
|
-
assert.deepStrictEqual(claimDeferredExecution({ inFlightPaymentAuthorizations: new Map() }, { ok: true }), { ok: true, key: null }, "non-deferred must be a no-op claim");
|
|
88
|
-
// Key derivation.
|
|
89
|
-
const verification = { deferred_settlement: { protocol: "x402_facilitator", authorization: { paymentPayload: { payload: { authorization: { from: "0xABC", nonce: "0xDEAD" } } } } } };
|
|
90
|
-
assert.strictEqual(deferredAuthorizationKey(verification), "x402:0xabc:0xdead", "key must be lowercased from:nonce");
|
|
91
|
-
// Fail open with no store.
|
|
92
|
-
assert.deepStrictEqual(claimDeferredExecution({}, verification), { ok: true, key: null }, "missing store must fail open");
|
|
93
|
-
// In-flight duplicate rejected, then freed on release.
|
|
94
|
-
const state = { inFlightPaymentAuthorizations: new Map() };
|
|
95
|
-
const first = claimDeferredExecution(state, verification);
|
|
96
|
-
assert.strictEqual(first.ok, true, "first claim must succeed");
|
|
97
|
-
const dup = claimDeferredExecution(state, verification);
|
|
98
|
-
assert.strictEqual(dup.ok, false, "second concurrent claim must be rejected");
|
|
99
|
-
assert.strictEqual(dup.status, 409, "duplicate must be 409");
|
|
100
|
-
assert.strictEqual(dup.reason, "payment_authorization_in_progress", "duplicate reason");
|
|
101
|
-
releaseDeferredExecution(state, first.key);
|
|
102
|
-
assert.strictEqual(claimDeferredExecution(state, verification).ok, true, "claim must succeed again after release");
|
|
103
|
-
// TTL prune: an expired entry is forgotten on the next claim.
|
|
104
|
-
const stale = { inFlightPaymentAuthorizations: new Map([["x402:0xabc:0xdead", { status: "in_flight", expires_at: Date.now() - 1 }]]) };
|
|
105
|
-
assert.strictEqual(claimDeferredExecution(stale, verification).ok, true, "an expired slot must be pruned and re-claimable");
|
|
106
|
-
console.log(" ok: unit checks (no-op, key, fail-open, duplicate, release, ttl-prune)");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function main() {
|
|
110
|
-
runUnitChecks();
|
|
111
|
-
|
|
112
|
-
const mock = await startMockServer();
|
|
113
|
-
const mockBase = `http://127.0.0.1:${mock.port}`;
|
|
114
|
-
const prev = {
|
|
115
|
-
mode: process.env.XYTARA_PAYMENT_VERIFICATION_MODE,
|
|
116
|
-
accepts: process.env.XYTARA_X402_ACCEPTS_JSON,
|
|
117
|
-
facUrl: process.env.XYTARA_X402_FACILITATOR_URL,
|
|
118
|
-
targets: process.env.XYTARA_EXECUTION_TARGETS_JSON
|
|
119
|
-
};
|
|
120
|
-
process.env.XYTARA_PAYMENT_VERIFICATION_MODE = "x402_facilitator";
|
|
121
|
-
process.env.XYTARA_X402_ACCEPTS_JSON = JSON.stringify(ACCEPTS);
|
|
122
|
-
process.env.XYTARA_X402_FACILITATOR_URL = mockBase;
|
|
123
|
-
process.env.XYTARA_EXECUTION_TARGETS_JSON = JSON.stringify([
|
|
124
|
-
{ target_id: "exec_slow", task_ref: "exec.slow", endpoint_url: `${mockBase}/exec-slow` },
|
|
125
|
-
{ target_id: "exec_fail", task_ref: "exec.fail", endpoint_url: `${mockBase}/exec-fail` }
|
|
126
|
-
]);
|
|
127
|
-
|
|
128
|
-
delete require.cache[require.resolve("../server")];
|
|
129
|
-
const { createServer } = require("../server");
|
|
130
|
-
const server = createServer();
|
|
131
|
-
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
132
|
-
const baseUrl = `http://127.0.0.1:${server.address().port}`;
|
|
133
|
-
const execBody = { account_id: "acct_dedupe", command: "slow exec", task_ref: "exec.slow", body: { subject_id: "s-1" } };
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
// Two concurrent requests sharing ONE authorization (same nonce) -> one wins, one 409.
|
|
137
|
-
const sharedNonce = `0x${"ab".repeat(32)}`;
|
|
138
|
-
const [a, b] = await Promise.all([
|
|
139
|
-
post(baseUrl, "/x402/commands/execute", execBody, { "payment-signature": paymentHeader(sharedNonce) }),
|
|
140
|
-
post(baseUrl, "/x402/commands/execute", execBody, { "payment-signature": paymentHeader(sharedNonce) })
|
|
141
|
-
]);
|
|
142
|
-
const statuses = [a.status, b.status].sort();
|
|
143
|
-
assert.deepStrictEqual(statuses, [200, 409], `exactly one must win and one must 409, got ${statuses}`);
|
|
144
|
-
const winner = a.status === 200 ? a : b;
|
|
145
|
-
const loser = a.status === 409 ? a : b;
|
|
146
|
-
assert.strictEqual(loser.json.reason, "payment_authorization_in_progress", "the duplicate must report in_progress");
|
|
147
|
-
assert.strictEqual(loser.json.payment_settled, false, "the rejected duplicate must not be charged");
|
|
148
|
-
assert.strictEqual(loser.receipt, null, "the rejected duplicate must carry no receipt");
|
|
149
|
-
assert.strictEqual(typeof winner.receipt, "string", "the winner must carry a settlement receipt");
|
|
150
|
-
assert.strictEqual(mock.calls.execSlow, 1, "the external target must have executed exactly once");
|
|
151
|
-
assert.strictEqual(mock.calls.settle, 1, "settlement must have happened exactly once");
|
|
152
|
-
|
|
153
|
-
// A different authorization (fresh nonce) is not blocked.
|
|
154
|
-
const other = await post(baseUrl, "/x402/commands/execute", execBody, { "payment-signature": paymentHeader(`0x${"cd".repeat(32)}`) });
|
|
155
|
-
assert.strictEqual(other.status, 200, "a distinct authorization must not be blocked");
|
|
156
|
-
assert.strictEqual(mock.calls.execSlow, 2, "the distinct authorization must execute");
|
|
157
|
-
|
|
158
|
-
console.log(" ok: concurrent same-authorization -> one execution, one settle, duplicate 409");
|
|
159
|
-
|
|
160
|
-
// Slot is released on a FAILED call, so a legitimate retry (even reusing the same
|
|
161
|
-
// still-unspent nonce) is not wrongly 409'd. Two SEQUENTIAL same-nonce calls to a
|
|
162
|
-
// failing executor must BOTH reach execution and neither be charged.
|
|
163
|
-
const failNonce = `0x${"ef".repeat(32)}`;
|
|
164
|
-
const failBody = { account_id: "acct_dedupe", command: "failing exec", task_ref: "exec.fail", body: { subject_id: "s-2" } };
|
|
165
|
-
const f1 = await post(baseUrl, "/x402/commands/execute", failBody, { "payment-signature": paymentHeader(failNonce) });
|
|
166
|
-
const f2 = await post(baseUrl, "/x402/commands/execute", failBody, { "payment-signature": paymentHeader(failNonce) });
|
|
167
|
-
assert.strictEqual(f1.status, 502, "first failing call must 502 (not 409)");
|
|
168
|
-
assert.strictEqual(f2.status, 502, "retry after failure must reach execution, not be blocked as a duplicate");
|
|
169
|
-
assert.strictEqual(f1.json.payment_settled, false, "failed call must not be charged");
|
|
170
|
-
assert.strictEqual(f2.json.payment_settled, false, "retry must not be charged");
|
|
171
|
-
assert.strictEqual(mock.calls.execFail, 2, "both failing attempts must have executed (slot released each time)");
|
|
172
|
-
console.log(" ok: failed call releases the slot -> retry not blocked, nothing charged");
|
|
173
|
-
|
|
174
|
-
console.log("xytara verify:execution-dedupe passed");
|
|
175
|
-
} finally {
|
|
176
|
-
await new Promise((resolve) => server.close(resolve));
|
|
177
|
-
await new Promise((resolve) => mock.server.close(resolve));
|
|
178
|
-
const restore = (k, v) => { if (v === undefined) delete process.env[k]; else process.env[k] = v; };
|
|
179
|
-
restore("XYTARA_PAYMENT_VERIFICATION_MODE", prev.mode);
|
|
180
|
-
restore("XYTARA_X402_ACCEPTS_JSON", prev.accepts);
|
|
181
|
-
restore("XYTARA_X402_FACILITATOR_URL", prev.facUrl);
|
|
182
|
-
restore("XYTARA_EXECUTION_TARGETS_JSON", prev.targets);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
main().catch((error) => {
|
|
187
|
-
console.error(error && error.message ? error.message : error);
|
|
188
|
-
process.exitCode = 1;
|
|
189
|
-
});
|