@coinbase/coinbase-cli 0.0.5 → 0.0.6
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var co=Object.defineProperty;var _o=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var I=(t,e)=>()=>(t&&(e=t(t=0)),e);var jt=(t,e)=>{for(var r in e)co(t,r,{get:e[r],enumerable:!0})};var y,g=I(()=>{y={live:{brokerageApi:"https://api.coinbase.com",agentApi:"https://agents.coinbase.com/api"}}});var b,l=I(()=>{b={production:"live"}});var lo,en,ge,rn,nn,le=I(()=>{"use strict";g();l();lo="https://agents.coinbase.com/api",en="@coinbase/coinbase-cli",ge="https://registry.npmjs.org",rn=typeof y<"u"?y:{live:{brokerageApi:"https://api.coinbase.com",agentApi:lo}},nn=typeof b<"u"?b:{production:"live"}});function Rt(t){return Qe+Buffer.from(t,"utf8").toString("base64")}function Pt(t){return t.startsWith(Qe)?Buffer.from(t.slice(Qe.length),"base64").toString("utf8"):t}var Qe,pe=I(()=>{"use strict";g();l();Qe="b64:"});import{execFileSync as me}from"node:child_process";var fe,ye,sn=I(()=>{"use strict";g();l();pe();fe="/usr/bin/security",ye=class{constructor(){try{me(fe,["list-keychains"],{stdio:["pipe","pipe","pipe"]})}catch{throw new Error("Keychain not accessible")}}get(e,r){try{let n=me(fe,["find-generic-password","-s",e,"-a",r,"-w"],{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trimEnd();return Pt(n)}catch{return null}}set(e,r,n){me(fe,["add-generic-password","-U","-s",e,"-a",r,"-w",Rt(n)],{stdio:["pipe","pipe","pipe"]})}delete(e,r){try{me(fe,["delete-generic-password","-s",e,"-a",r],{stdio:["pipe","pipe","pipe"]})}catch{}}}});import{execFileSync as be}from"node:child_process";var he,on=I(()=>{"use strict";g();l();pe();he=class{constructor(){try{be("which",["secret-tool"],{stdio:["pipe","pipe","pipe"]})}catch{throw new Error("secret-tool not found")}}get(e,r){try{let n=be("secret-tool",["lookup","service",e,"account",r],{encoding:"utf8",stdio:["pipe","pipe","pipe"]});return Pt(n.trimEnd())}catch{return null}}set(e,r,n){be("secret-tool",["store","--label",`${e}:${r}`,"service",e,"account",r],{input:Rt(n),stdio:["pipe","pipe","pipe"]})}delete(e,r){try{be("secret-tool",["clear","service",e,"account",r],{stdio:["pipe","pipe","pipe"]})}catch{}}}});import{execFileSync as po}from"node:child_process";function Je(t,e){return`${t}:${e}`}function Ee(t){return t.replace(/'/g,"''")}function Xe(t,e){let r=mo+t,n=Buffer.from(r,"utf16le").toString("base64"),i=e===void 0?process.env:{...process.env,[an]:e};return po("powershell.exe",["-NoProfile","-NonInteractive","-EncodedCommand",n],{encoding:"utf8",stdio:["pipe","pipe","pipe"],env:i}).trimEnd()}var mo,an,Ie,cn=I(()=>{"use strict";g();l();pe();mo=`
|
|
3
3
|
if (-not ([System.Management.Automation.PSTypeName]'Win32.Cred').Type) {
|
|
4
4
|
Add-Type -Namespace Win32 -Name Cred -MemberDefinition '
|
|
5
5
|
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
|
@@ -17,7 +17,7 @@ if (-not ([System.Management.Automation.PSTypeName]'Win32.Cred').Type) {
|
|
|
17
17
|
public string TargetAlias; public string UserName;
|
|
18
18
|
}'
|
|
19
19
|
}
|
|
20
|
-
`,
|
|
20
|
+
`,an="COINBASE_KEYRING_SECRET";Ie=class{get(e,r){try{let n=Ee(Je(e,r)),i=Xe(`
|
|
21
21
|
$ptr = [IntPtr]::Zero
|
|
22
22
|
if ([Win32.Cred]::CredRead('${n}', 1, 0, [ref]$ptr)) {
|
|
23
23
|
$cred = [Runtime.InteropServices.Marshal]::PtrToStructure($ptr, [Type][Win32.Cred+CREDENTIAL])
|
|
@@ -25,8 +25,8 @@ if ([Win32.Cred]::CredRead('${n}', 1, 0, [ref]$ptr)) {
|
|
|
25
25
|
[Runtime.InteropServices.Marshal]::Copy($cred.CredentialBlob, $bytes, 0, $cred.CredentialBlobSize)
|
|
26
26
|
[Win32.Cred]::CredFree($ptr)
|
|
27
27
|
[Text.Encoding]::UTF8.GetString($bytes)
|
|
28
|
-
}`);return i?Pt(i):null}catch{return null}}set(e,r,n){let i=
|
|
29
|
-
$sec = $env:${
|
|
28
|
+
}`);return i?Pt(i):null}catch{return null}}set(e,r,n){let i=Ee(Je(e,r)),s=Ee(r);Xe(`
|
|
29
|
+
$sec = $env:${an}
|
|
30
30
|
$bytes = [Text.Encoding]::UTF8.GetBytes($sec)
|
|
31
31
|
$blob = [Runtime.InteropServices.Marshal]::AllocHGlobal($bytes.Length)
|
|
32
32
|
[Runtime.InteropServices.Marshal]::Copy($bytes, 0, $blob, $bytes.Length)
|
|
@@ -40,95 +40,95 @@ $cred.Persist = 2
|
|
|
40
40
|
if (-not [Win32.Cred]::CredWrite([ref]$cred, 0)) {
|
|
41
41
|
throw "CredWrite failed: $([Runtime.InteropServices.Marshal]::GetLastWin32Error())"
|
|
42
42
|
}
|
|
43
|
-
[Runtime.InteropServices.Marshal]::FreeHGlobal($blob)`,Rt(n))}delete(e,r){try{
|
|
44
|
-
`),
|
|
45
|
-
Re-run the env-setup command with --allow-plaintext-secrets to write secrets to ${
|
|
46
|
-
`,{mode:384}),
|
|
47
|
-
`)}let o=Z(n,r),a=lt(n,r);if(!o&&!a)throw new Error(`no REST endpoint for environment "${r}". Set a brokerage URL, an Agent API URL, or use a built-in environment name`);if(!n.auth)throw new Error(`no credentials for "${r}". Run: coinbase env ${r} --key-file path/to/key.json`);return{name:r,env:n}}function or(){let t={...process.env};for(let e of To)delete t[e];return t}function ve(t){return process.env.COINBASE_NO_HISTORY?!1:t.settings?.history?.enabled!==!1}function ar(t,e,r,n){t.history[e]||(t.history[e]={}),t.history[e][r]={last_used:new Date().toISOString(),values:n}}function cr(t,e,r){return t.history[e]?.[r]}function Xt(t,e,r){if(e&&r)return t.history[e]?.[r]?(delete t.history[e][r],Object.keys(t.history[e]).length===0&&delete t.history[e],1):0;if(e){let i=Object.keys(t.history[e]??{}).length;return delete t.history[e],i}let n=Object.values(t.history).reduce((i,s)=>i+Object.keys(s).length,0);return t.history={},n}var X,mn,xt,Io,Tt,tr,er,To,tt=I(()=>{"use strict";g();l();ge();Xe();X=en,mn=rn;xt={cdp_key:{secrets:{key_secret:t=>`${t}:cdp:key_secret`},metadataOnly:t=>({type:"cdp_key",key_id:t.key_id})}};Io=".lock",Tt={retries:50,baseDelayMs:20,staleAfterMs:5e3};To=["COINBASE_KEY_SECRET","COINBASE_KEY_ID"]});function Go(t,e,r){let n=new Date(Date.UTC(t,e-1,r));return n.getUTCFullYear()===t&&n.getUTCMonth()===e-1&&n.getUTCDate()===r}var rt,nt,On,Rn,Pn,Ct=I(()=>{"use strict";g();l();rt=[{name:"convert",actions:[{id:"convert_quote",name:"quote",method:"POST",path:"/convert/quote",summary:"Get Convert Quote",description:"Quotes a currency conversion (e.g. stablecoin pairs), returning rate, fees, and a quote id. Read-only preview \u2014 pass the id to convert_execute to commit; quotes expire, so execute promptly.",pathParams:[],params:[{name:"from",in:"body",type:"string",required:!0,description:"Source currency",example:"USDC"},{name:"to",in:"body",type:"string",required:!0,description:"Target currency",example:"USD"},{name:"amount",in:"body",type:"string",required:!0,description:"Amount to convert",example:"100.00"}],streamable:!1,watchFields:null,template:{from:"USDC",to:"USD",amount:"100.00"},responseFields:{fields:["trade"],nested:{trade:{fields:["id","status","amount","subtotal","total","total_fee","exchange_rate","source_currency","target_currency"]}}}},{id:"convert_execute",name:"execute",method:"POST",path:"/convert/execute/{quote_id}",summary:"Execute Convert Trade",description:"Executes a previously quoted conversion using the quote id from convert_quote. This moves funds at the quoted rate \u2014 always get a fresh quote first, since quotes expire. The from/to currencies must match the original quote.",pathParams:["quote_id"],params:[{name:"quote_id",in:"path",type:"string",required:!0,description:"Quote ID from convert quote response"},{name:"from",in:"body",type:"string",required:!0,description:"Source currency",example:"USDC"},{name:"to",in:"body",type:"string",required:!0,description:"Target currency",example:"USD"}],streamable:!1,watchFields:null,template:{from:"USDC",to:"USD"},responseFields:{fields:["trade"],nested:{trade:{fields:["id","status"]}}}},{id:"convert_get",name:"get",method:"GET",path:"/convert/get/{quote_id}",summary:"Get Convert Status",description:"Check status of a conversion by quote ID.",pathParams:["quote_id"],params:[{name:"quote_id",in:"path",type:"string",required:!0,description:"Quote ID"},{name:"from",in:"query",type:"string",required:!0,description:"Source currency"},{name:"to",in:"query",type:"string",required:!0,description:"Target currency"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["id","status","source_currency","target_currency","exchange_rate"]}}]},{name:"orders",actions:[{id:"orders_list",name:"list",method:"GET",path:"/orders",summary:"List Orders",description:"Lists orders with optional filters by status, product, side, and time range. Read-only. Use status=OPEN to find resting orders that can be edited or cancelled.",pathParams:[],params:[{name:"status",in:"query",type:"string",required:!1,description:"Filter by status"},{name:"product_ids",in:"query",type:"array",required:!1,description:"Filter by product (e.g. BTC-USD). Comma-separated for multiple."},{name:"side",in:"query",type:"string",required:!1,description:"Filter by side",enum:["BUY","SELL"]},{name:"product_type",in:"query",type:"string",required:!1,description:"Filter by product type",enum:["SPOT","FUTURE"]},{name:"start",in:"query",type:"string",required:!1,description:"Start date (RFC 3339 with timezone, e.g. 2024-01-01T00:00:00Z)",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End date (RFC 3339 with timezone, e.g. 2024-12-31T23:59:59Z)",format:"date-time"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!0,watchFields:{status:{type:"string",enum:["PENDING","OPEN","FILLED","CANCELLED","FAILED","EXPIRED","CANCEL_QUEUED"],description:"Order status"},side:{type:"string",enum:["BUY","SELL"],description:"Order side"},price:{type:"number",description:"Average filled price"},filled_size:{type:"number",description:"Filled quantity"},fees:{type:"number",description:"Total fees"},product_id:{type:"string",description:"Trading pair"},order_id:{type:"string",description:"Order ID"}},template:{},responseFields:{fields:["orders","has_next","cursor"],nested:{orders:{fields:["order_id","product_id","side","status","order_configuration","created_time","completion_percentage","filled_size","average_filled_price","total_fees","total_value_after_fees","number_of_fills"]}}},agentApi:"eligible",agentQueryTransforms:{product_ids:"join-comma"}},{id:"orders_create",name:"create",method:"POST",path:"/orders",summary:"Create Order",description:"Places a live order \u2014 executes immediately and moves funds (market buy spends quote currency; sell disposes of base). Preview with orders_preview first to estimate fees, fill price, and slippage.",pathParams:[],params:[{name:"product_id",in:"body",type:"string",required:!0,description:"Trading pair (BASE-QUOTE). Use the quote currency the user names (e.g. USDC); never default to USD. If unspecified, check balance; prefer USDC if both held. Tell the user if the pair is unavailable.",example:"BASE-QUOTE"},{name:"side",in:"body",type:"string",required:!0,description:"BUY or SELL",enum:["BUY","SELL"],example:"BUY"},{name:"type",in:"body",type:"string",required:!0,description:"market = fill now; limit = fill at price or better; stop_limit = limit triggered at stop_price",enum:["market","limit","stop_limit"],example:"market"},{name:"quote_size",in:"body",type:"string",required:!1,description:"Quote currency amount (e.g. spend $100 USD). Market buy only. Mutually exclusive with base_size.",oneOf:"base_size|quote_size",example:"100.00"},{name:"base_size",in:"body",type:"string",required:!1,description:"Base currency amount (e.g. buy 0.001 BTC). Any side/type.",oneOf:"base_size|quote_size",example:"0.001"},{name:"limit_price",in:"body",type:"string",required:!1,description:"Limit price (limit/stop_limit orders)",example:"65000.00"},{name:"stop_price",in:"body",type:"string",required:!1,description:"Stop price (stop_limit orders)",example:"60000.00"},{name:"stop_direction",in:"body",type:"string",required:!1,description:"up = trigger when price rises above stop_price. down = trigger when falls below.",enum:["up","down"],example:"down"},{name:"post_only",in:"body",type:"boolean",required:!1,description:"Post-only mode (limit orders). Rejects if would take liquidity."},{name:"time_in_force",in:"body",type:"string",required:!1,description:"GTC=good til cancelled. IOC=immediate or cancel. FOK=fill or kill.",enum:["GTC","IOC","FOK","GTD"],example:"GTC"},{name:"end_time",in:"body",type:"string",required:!1,description:"Expiry time for GTD orders (RFC 3339). Required when time_in_force=GTD.",format:"date-time",example:"2024-12-31T23:59:59Z"},{name:"reduce_only",in:"body",type:"boolean",required:!1,description:"Only reduce existing position. Rejects if would increase exposure."},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Scopes the order to a specific portfolio (defaults to auth-scoped portfolio)"},{name:"client_order_id",in:"body",type:"string",required:!1,description:"Idempotency key (auto-generated if omitted)"}],streamable:!1,watchFields:null,template:{product_id:"BASE-QUOTE",side:"BUY",type:"market",quote_size:"100.00",base_size:"0.001",limit_price:"65000.00",stop_price:"60000.00",stop_direction:"up",post_only:!1,time_in_force:"GTC",end_time:"2024-12-31T23:59:59Z",reduce_only:!1,portfolio_id:"<string>",client_order_id:"<string>"},responseFields:{fields:["order_id","product_id","side","client_order_id"]},agentApi:"eligible"},{id:"orders_preview",name:"preview",method:"POST",path:"/orders/preview",summary:"Preview Order",description:"Estimate fees, fill price, and slippage without executing.",pathParams:[],params:[{name:"product_id",in:"body",type:"string",required:!0,description:"Trading pair (BASE-QUOTE). Use the quote currency the user names (e.g. USDC); never default to USD. If unspecified, check balance; prefer USDC if both held. Tell the user if the pair is unavailable.",example:"BASE-QUOTE"},{name:"side",in:"body",type:"string",required:!0,description:"BUY or SELL",enum:["BUY","SELL"],example:"BUY"},{name:"type",in:"body",type:"string",required:!0,description:"market = fill now; limit = fill at price or better; stop_limit = limit triggered at stop_price",enum:["market","limit","stop_limit"],example:"market"},{name:"quote_size",in:"body",type:"string",required:!1,description:"Quote currency amount (e.g. spend $100 USD). Mutually exclusive with base_size.",oneOf:"base_size|quote_size",example:"100.00"},{name:"base_size",in:"body",type:"string",required:!1,description:"Base currency amount (e.g. 0.001 BTC). Mutually exclusive with quote_size.",oneOf:"base_size|quote_size",example:"0.001"},{name:"limit_price",in:"body",type:"string",required:!1,description:"Limit price (for limit/stop_limit previews)",example:"65000.00"},{name:"stop_price",in:"body",type:"string",required:!1,description:"Stop price (for stop_limit previews)",example:"60000.00"},{name:"stop_direction",in:"body",type:"string",required:!1,description:"up = trigger when price rises above stop_price. down = trigger when falls below.",enum:["up","down"],example:"down"}],streamable:!1,watchFields:null,template:{product_id:"BASE-QUOTE",side:"BUY",type:"market",quote_size:"100.00",base_size:"0.001",limit_price:"65000.00",stop_price:"60000.00",stop_direction:"up"},responseFields:{fields:["order_total","commission_total","slippage","est_average_filled_price","base_size","quote_size","best_bid","best_ask"]},agentApi:"eligible"},{id:"orders_edit",name:"edit",method:"POST",path:"/orders/edit/{order_id}",summary:"Edit Order",description:"Atomically update an open order's price or size without cancelling. Avoids the cancel+replace exposure window.",pathParams:["order_id"],params:[{name:"order_id",in:"path",type:"string",required:!0,description:"Order to edit"},{name:"base_size",in:"body",type:"string",required:!1,description:"New base size",example:"0.002"},{name:"limit_price",in:"body",type:"string",required:!1,description:"New limit price",example:"64000.00"}],streamable:!1,watchFields:null,template:{base_size:"0.002",limit_price:"64000.00"},responseFields:{fields:["order_id","status"]},agentApi:"eligible",agentPath:"/orders/edit"},{id:"orders_get",name:"get",method:"GET",path:"/orders/{order_id}",summary:"Get Order",description:"Retrieves the full status and fill details of a single order by ID. Read-only. Use after creating an order to confirm execution.",pathParams:["order_id"],params:[{name:"order_id",in:"path",type:"string",required:!0,description:"Order ID"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["order_id","product_id","side","status","order_configuration","created_time","completion_percentage","filled_size","average_filled_price","total_fees","total_value_after_fees","number_of_fills"]},agentApi:"eligible"},{id:"orders_cancel",name:"cancel",method:"POST",path:"/orders/cancel",summary:"Cancel Orders",description:"Cancels one or more open orders by ID. Removes resting orders from the book so reserved funds are released; already-filled portions are unaffected. Returns per-order success so a partial batch can fail.",pathParams:[],params:[{name:"order_ids",in:"body",type:"array",required:!0,description:"Order IDs to cancel"}],streamable:!1,watchFields:null,template:{order_ids:[]},responseFields:{fields:["results"],nested:{results:{fields:["success","order_id"]}}},agentApi:"eligible"},{id:"orders_close_position",name:"close-position",method:"POST",path:"/orders/close-position",summary:"Close Position",description:"Places a market order to flatten an open position for a product, moving funds immediately. Omit size for a full close or set it for a partial close. Preview the equivalent order first if fee or slippage impact matters.",pathParams:[],params:[{name:"client_order_id",in:"body",type:"string",required:!0,description:"Idempotency key"},{name:"product_id",in:"body",type:"string",required:!0,description:"Product to close",example:"BTC-PERP"},{name:"size",in:"body",type:"string",required:!1,description:"Partial close size (omit for full close)",example:"0.001"}],streamable:!1,watchFields:null,template:{client_order_id:"<string>",product_id:"BTC-PERP",size:"0.001"},responseFields:null,agentApi:"eligible"},{id:"orders_fills",name:"fills",method:"GET",path:"/orders/fills",summary:"List Fills",description:"Lists individual trade executions (fills) with commissions and maker/taker indicator, filterable by product, order, side, and time range. Read-only. Use this to reconcile actual fill prices and fees paid.",pathParams:[],params:[{name:"product_ids",in:"query",type:"array",required:!1,description:"Filter by product (e.g. BTC-USD)"},{name:"order_ids",in:"query",type:"string",required:!1,description:"Filter by order ID"},{name:"start",in:"query",type:"string",required:!1,description:"Start time (RFC 3339 with timezone, e.g. 2024-01-01T00:00:00Z)",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End time (RFC 3339 with timezone, e.g. 2024-12-31T23:59:59Z)",format:"date-time"},{name:"side",in:"query",type:"string",required:!1,description:"Filter by side",enum:["BUY","SELL"]},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["fills","cursor"],nested:{fills:{fields:["trade_id","order_id","trade_time","price","size","commission","product_id","side","liquidity_indicator"]}}},agentApi:"eligible",agentQueryTransforms:{product_ids:"join-comma",order_ids:"split-comma"}}]},{name:"portfolios",actions:[{id:"portfolios_list",name:"list",method:"GET",path:"/portfolios",summary:"List Portfolios",description:"Lists all portfolios on the account, including their UUIDs and types. Read-only. Use this to find the portfolio_id needed for orders, transfers, and balance queries.",pathParams:[],params:[{name:"portfolio_type",in:"query",type:"string",required:!1,description:"Filter by type (DEFAULT, CONSUMER, INTX)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["portfolios"],nested:{portfolios:{fields:["uuid","name","type","deleted"]}}}},{id:"portfolios_create",name:"create",method:"POST",path:"/portfolios",summary:"Create Portfolio",description:"Creates a new named portfolio for segregating funds and positions. Does not move any funds; use transfer afterward to fund it.",pathParams:[],params:[{name:"name",in:"body",type:"string",required:!0,description:"Portfolio name",example:"agent-1"}],streamable:!1,watchFields:null,template:{name:"agent-1"},responseFields:{fields:["uuid","name","type","deleted"]}},{id:"portfolios_get",name:"get",method:"GET",path:"/portfolios/{portfolio_id}",summary:"Get Portfolio Breakdown",description:"Returns portfolio metadata, balances, and positions.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"},{name:"currency",in:"query",type:"string",required:!1,description:"Currency for balance denomination"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["portfolio","portfolio_balances","spot_positions"],nested:{portfolio:{fields:["uuid","name","type","deleted"]},portfolio_balances:{fields:["total_balance","total_crypto_balance","total_cash_equivalent_balance"],nested:{total_balance:{fields:["value","currency"]},total_crypto_balance:{fields:["value","currency"]},total_cash_equivalent_balance:{fields:["value","currency"]}}},spot_positions:{fields:["asset","account_uuid","total_balance_fiat","total_balance_crypto","available_to_trade_fiat","allocation","is_cash"]}}},agentApi:"eligible"},{id:"portfolios_edit",name:"edit",method:"PUT",path:"/portfolios/{portfolio_id}",summary:"Edit Portfolio",description:"Renames an existing portfolio. Metadata-only change; does not affect balances or positions.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"},{name:"name",in:"body",type:"string",required:!1,description:"New portfolio name"}],streamable:!1,watchFields:null,template:{name:"<string>"},responseFields:{fields:["uuid","name","type","deleted"]}},{id:"portfolios_delete",name:"delete",method:"DELETE",path:"/portfolios/{portfolio_id}",summary:"Delete Portfolio",description:"Permanently deletes a portfolio. The portfolio must be empty first \u2014 transfer out any remaining funds and close all positions before deleting. The DEFAULT portfolio cannot be deleted.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"}],streamable:!1,watchFields:null,template:{},responseFields:null}]},{name:"products",actions:[{id:"products_list",name:"list",method:"GET",path:"/products",summary:"List Products",description:"Lists tradable products and their current price and 24h stats, optionally filtered by symbol or type. Read-only. Use to discover valid product_id values before placing orders.",pathParams:[],params:[{name:"symbol",in:"query",type:"string",required:!1,description:"Filter products by symbol, matches base or quote side (e.g. USD, BTC). For a specific product use `get` (e.g. BTC-USD). Pagination ignored when set.",pattern:"^[A-Za-z0-9]+$"},{name:"product_type",in:"query",type:"string",required:!1,description:"Product type filter",enum:["SPOT","FUTURE"]},{name:"product_ids",in:"query",type:"array",required:!1,description:"Comma-separated product IDs"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["products","cursor","has_next","num_products"],nested:{products:{fields:["product_id","price","price_percentage_change_24h","volume_24h","product_type","quote_currency_id","base_currency_id","base_increment","quote_increment","base_min_size","base_max_size","quote_min_size","quote_max_size","status"]}}}},{id:"products_get",name:"get",method:"GET",path:"/products/{product_id}",summary:"Get Product",description:"Returns full details for a single product, including price and trading increments/min sizes. Read-only. Use base_increment and base_min_size to size orders that the exchange will accept.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Product ID (e.g. BTC-USD)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["product_id","price","price_percentage_change_24h","volume_24h","product_type","quote_currency_id","base_currency_id","base_increment","quote_increment","base_min_size","base_max_size","quote_min_size","quote_max_size","status"]},agentApi:"eligible"},{id:"products_ticker",name:"ticker",method:"GET",path:"/products/{product_id}/ticker",summary:"Get Ticker",description:"Returns recent trades plus the current best bid and ask for a product. Read-only. Use for a quick spot price snapshot before previewing or placing an order.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Trading pair (e.g. BTC-USD)"},{name:"limit",in:"query",type:"integer",required:!1,description:"Number of trades. Defaults to 100."}],streamable:!0,watchFields:{price:{type:"number",description:"Last trade price"},bid:{type:"number",description:"Best bid"},ask:{type:"number",description:"Best ask"},bid_size:{type:"number",description:"Size at best bid"},ask_size:{type:"number",description:"Size at best ask"},volume:{type:"number",description:"24h volume"},high:{type:"number",description:"24h high"},low:{type:"number",description:"24h low"},pct_24h:{type:"number",description:"24h price change %"},product_id:{type:"string",description:"Trading pair"}},template:{},responseFields:{fields:["trades","best_bid","best_ask"],nested:{trades:{fields:["trade_id","product_id","price","size","time","side"]}}}},{id:"products_book",name:"book",method:"GET",path:"/products/{product_id}/book",summary:"Get Order Book",description:"Returns the bid/ask order book (price levels and sizes) for a product. Read-only. Use to gauge available liquidity and likely slippage before sizing a market order.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Product ID"},{name:"limit",in:"query",type:"integer",required:!1,description:"Number of levels"}],streamable:!0,watchFields:{spread:{type:"number",description:"Bid-ask spread"},mid:{type:"number",description:"Midpoint price"},product_id:{type:"string",description:"Trading pair"}},template:{},responseFields:{fields:["pricebook"],nested:{pricebook:{fields:["product_id","bids","asks","time"],nested:{bids:{fields:["price","size"]},asks:{fields:["price","size"]}}}}}},{id:"products_candles",name:"candles",method:"GET",path:"/products/{product_id}/candles",summary:"Get Candles",description:"Returns historical OHLCV candles for a product at a chosen granularity and time range. Read-only. Use for price history and technical analysis.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Trading pair (e.g. BTC-USD)"},{name:"start",in:"query",type:"string",required:!1,description:"Start time (RFC 3339, e.g. 2024-01-01T00:00:00Z). Defaults to 60 candles before end.",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End time (RFC 3339, e.g. 2024-01-01T00:00:00Z). Defaults to now.",format:"date-time"},{name:"granularity",in:"query",type:"string",required:!1,description:"Candle interval: 1m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 1d. Defaults to 1h.",enum:["1m","5m","15m","30m","1h","2h","4h","6h","1d"],default:"1h"},{name:"limit",in:"query",type:"integer",required:!1,description:"Max candles"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["candles"],nested:{candles:{fields:["start","low","high","open","close","volume"]}}}},{id:"products_best_bid_ask",name:"best-bid-ask",method:"GET",path:"/products/best-bid-ask",summary:"Best Bid/Ask for Multiple Products",description:"Returns best bid and ask for one or more products in a single call.",pathParams:[],params:[{name:"product_ids",in:"query",type:"array",required:!1,description:"Comma-separated product IDs (e.g. BTC-USD,ETH-USD)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["pricebooks"],nested:{pricebooks:{fields:["product_id","bids","asks","time"],nested:{bids:{fields:["price","size"]},asks:{fields:["price","size"]}}}}}}]},{name:"x402",actions:[{id:"x402_resources",name:"resources",method:"GET",path:"/x402/resources",summary:"Discover x402 Resources",description:"Discover curated x402-enabled resources. Discovery does not spend funds; use the returned payment requirements as budget hints and the input schema to call a resource.",pathParams:[],params:[{name:"q",in:"query",type:"string",required:!1,description:"Optional keyword filter over resource descriptions, providers, and tags"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["resources"],nested:{resources:{fields:["resource","description","accepts","inputSchema","outputSchema"],nested:{accepts:{fields:["amount"]}}}}},agentApi:"only"},{id:"x402_pay",name:"pay",method:"POST",path:"/x402/pay",summary:"Pay an x402 Payment Requirement",description:"Creates a ready-to-send x402 payment header by placing a USDC hold. This moves funds; use the smallest amount that satisfies the requirement and reuse idempotency_key only when retrying the same payment.",pathParams:[],params:[{name:"scheme",in:"body",type:"string",required:!0,description:"x402 payment scheme (currently exact)"},{name:"network",in:"body",type:"string",required:!0,description:"CAIP-2 network (currently eip155:8453)"},{name:"asset",in:"body",type:"string",required:!0,description:"USDC asset contract address"},{name:"pay_to",in:"body",type:"string",required:!0,description:"Recipient address"},{name:"amount",in:"body",type:"string",required:!0,description:"Required atomic-unit amount from the x402 challenge"},{name:"max_amount",in:"body",type:"string",required:!0,description:"Caller spend cap in atomic units"},{name:"max_timeout_seconds",in:"body",type:"integer",required:!0,description:"Authorization validity window in seconds"},{name:"x402_version",in:"body",type:"integer",required:!1,description:"x402 protocol version; defaults to 2",default:2},{name:"extra",in:"body",type:"object",required:!1,description:"EIP-712 domain; required by protocol semantics for x402_version 2"},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Optional portfolio UUID to pay from"},{name:"account_id",in:"body",type:"string",required:!1,description:"Optional USDC account UUID to debit"},{name:"idempotency_key",in:"body",type:"string",required:!1,description:"Reuse only to retry the same logical payment"}],streamable:!1,watchFields:null,template:{scheme:"<string>",network:"<string>",asset:"<string>",pay_to:"<string>",amount:"<string>",max_amount:"<string>",max_timeout_seconds:0,x402_version:2,extra:{name:"<string>",version:"<string>"},portfolio_id:"<string>",account_id:"<string>",idempotency_key:"<string>"},responseFields:{fields:["payment_header","payment_id","idempotency_key","expires_at"]},history:"disabled",agentApi:"only"},{id:"x402_fetch",name:"fetch",method:"POST",path:"/x402/fetch",summary:"Pay For and Fetch x402 Resource",description:"Fetches a resource returned by x402 resources. On a 402 challenge, the Agent API pays from custodial USDC and retries automatically. Only catalog URLs and catalog-declared input fields are accepted; input is sent as query parameters for GET resources and as JSON for POST resources. Protocol v2 only. max_amount optionally tightens the catalog advisory ceiling, which is enforced when omitted.",pathParams:[],params:[{name:"resource",in:"body",type:"string",required:!0,description:"Exact URL returned by x402 resources"},{name:"input",in:"body",type:"object",required:!1,description:"Request parameters validated against the resource catalog schema"},{name:"max_amount",in:"body",type:"string",required:!1,description:"Optional caller cap; catalog advisory ceiling applies when omitted"},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Optional portfolio UUID to pay from"},{name:"account_id",in:"body",type:"string",required:!1,description:"Optional USDC account UUID to debit"},{name:"idempotency_key",in:"body",type:"string",required:!1,description:"Reuse only to retry the same logical fetch"}],streamable:!1,watchFields:null,template:{resource:"<string>",input:{},max_amount:"<string>",portfolio_id:"<string>",account_id:"<string>",idempotency_key:"<string>"},responseFields:{fields:["data","paid","payment_id","idempotency_key","expires_at"]},history:"disabled",agentApi:"only"}]}],nt={balance:{id:"balance",name:"balance",method:"GET",path:"/balance",summary:"View Balances",description:"Lists account balances across currencies, showing available funds and amounts on hold. Read-only. Use before trading or transferring to confirm available funds; available_balance excludes funds held by open orders.",pathParams:[],params:[{name:"portfolio_id",in:"query",type:"string",required:!1,description:"Filter by portfolio"},{name:"show_zero",in:"query",type:"boolean",required:!1,description:"Include zero-balance accounts (default false)"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["accounts","has_next","cursor","size"],nested:{accounts:{fields:["uuid","name","currency","available_balance","hold","type","active","ready"],nested:{available_balance:{fields:["value","currency"]},hold:{fields:["value","currency"]}}}}}},transfer:{id:"transfer",name:"transfer",method:"POST",path:"/transfer",summary:"Move Funds Between Portfolios",description:"Moves funds of a single currency from one portfolio to another. This executes immediately and moves money \u2014 verify the source has sufficient available balance first. Both portfolio UUIDs come from portfolios_list.",pathParams:[],params:[{name:"amount",in:"body",type:"string",required:!0,description:"Amount to transfer",example:"100.00"},{name:"currency",in:"body",type:"string",required:!0,description:"Currency",example:"USD"},{name:"from",in:"body",type:"string",required:!0,description:"Source portfolio UUID",example:"d17b3486-..."},{name:"to",in:"body",type:"string",required:!0,description:"Target portfolio UUID",example:"a44ef7a8-..."}],streamable:!1,watchFields:null,template:{amount:"100.00",currency:"USD",from:"d17b3486-...",to:"a44ef7a8-..."},responseFields:{fields:["source_portfolio_uuid","target_portfolio_uuid"]}},fees:{id:"fees",name:"fees",method:"GET",path:"/fees",summary:"Fee Tier and Volume",description:"Fee tier, maker/taker rates, and 30-day volume.",pathParams:[],params:[{name:"product_type",in:"query",type:"string",required:!1,description:"Filter by product type",enum:["SPOT","FUTURE"]}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["total_fees","fee_tier","margin_rate","advanced_trade_only_volume","advanced_trade_only_fees","coinbase_pro_volume","coinbase_pro_fees","total_balance","has_cost_plus_commission"],nested:{fee_tier:{fields:["pricing_tier","taker_fee_rate","maker_fee_rate"]}}}}},On=new Set(["balance","transfer","fees"]),Rn={"date-time":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/};Pn={"date-time":t=>{let e=t.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/);if(!e)return!1;let[,r,n,i,s,o,a]=e;return Go(+r,+n,+i)&&+s<24&&+o<60&&+a<61}}});function dr(t){return typeof t=="object"&&"endpoint"in t}function C(t,e){return{endpoint:t,...e}}var It=I(()=>{"use strict";g();l()});var Tn,Sn,xn,wn,An,Cn,Nn,Gn,Dn,Ln,Mn,Fn,Un,qn,Bn,zn,Nt=I(()=>{"use strict";g();l();Tn={origin:"RetailBrokerageApi_CancelOrders",method:"POST",path:"/api/v3/brokerage/orders/batch_cancel"},Sn={origin:"RetailBrokerageApi_ClosePosition",method:"POST",path:"/api/v3/brokerage/orders/close_position"},xn={origin:"RetailBrokerageApi_CommitConvertTrade",method:"POST",path:"/api/v3/brokerage/convert/trade/{trade_id}"},wn={origin:"RetailBrokerageApi_CreatePortfolio",method:"POST",path:"/api/v3/brokerage/portfolios"},An={origin:"RetailBrokerageApi_DeletePortfolio",method:"DELETE",path:"/api/v3/brokerage/portfolios/{portfolio_uuid}"},Cn={origin:"RetailBrokerageApi_EditPortfolio",method:"PUT",path:"/api/v3/brokerage/portfolios/{portfolio_uuid}"},Nn={origin:"RetailBrokerageApi_GetBestBidAsk",method:"GET",path:"/api/v3/brokerage/best_bid_ask"},Gn={origin:"RetailBrokerageApi_GetConvertTrade",method:"GET",path:"/api/v3/brokerage/convert/trade/{trade_id}"},Dn={origin:"RetailBrokerageApi_GetFills",method:"GET",path:"/api/v3/brokerage/orders/historical/fills"},Ln={origin:"RetailBrokerageApi_GetHistoricalOrder",method:"GET",path:"/api/v3/brokerage/orders/historical/{order_id}"},Mn={origin:"RetailBrokerageApi_GetHistoricalOrders",method:"GET",path:"/api/v3/brokerage/orders/historical/batch"},Fn={origin:"RetailBrokerageApi_GetPortfolioBreakdown",method:"GET",path:"/api/v3/brokerage/portfolios/{portfolio_uuid}"},Un={origin:"RetailBrokerageApi_GetPortfolios",method:"GET",path:"/api/v3/brokerage/portfolios"},qn={origin:"RetailBrokerageApi_GetProduct",method:"GET",path:"/api/v3/brokerage/products/{product_id}"},Bn={origin:"RetailBrokerageApi_GetPublicProductBook",method:"GET",path:"/api/v3/brokerage/market/product_book"},zn={origin:"RetailBrokerageApi_GetTransactionSummary",method:"GET",path:"/api/v3/brokerage/transaction_summary"}});var Wn,$n=I(()=>{"use strict";g();l();It();Nt();Wn={portfolios_list:C(Un),portfolios_get:C(Fn,{requestMap:{portfolio_id:"portfolio_uuid"},responseUnwrap:"breakdown"}),portfolios_create:C(wn,{responseUnwrap:"portfolio"}),portfolios_edit:C(Cn,{requestMap:{portfolio_id:"portfolio_uuid"},responseUnwrap:"portfolio"}),portfolios_delete:C(An,{requestMap:{portfolio_id:"portfolio_uuid"}})}});var D,pt=I(()=>{"use strict";g();l();D=class t extends Error{status;correlationId;traceId;constructor(e,r,n){super(e),this.status=r,this.correlationId=n?.correlationId,this.traceId=n?.traceId}static stripGrpcPrefix(e){let r=e.match(/^rpc error: code = \w+ desc = (.+)$/s);return r?r[1]:e}static fromResponse(e,r,n){let i=new TextDecoder().decode(e),s,o;try{let c=JSON.parse(i);c.errorType&&c.errorMessage?s=`${c.errorType} \u2014 ${c.errorMessage}`:c.message?s=t.stripGrpcPrefix(c.message):s=i.length>200?i.slice(0,200)+"...":i,o=c.correlationId||c.correlation_id||void 0}catch{s=i.length>200?i.slice(0,200)+"...":i}let a=n?.get("trace-id")??void 0;return new t(s,r,{correlationId:o,traceId:a})}}});function gr(t){if(t?.success===!1){let e=t.error_response,r=t.errors?.[0]?.edit_failure_reason,n=e?.new_order_failure_reason?String(e.new_order_failure_reason).replace(/^NEW_ORDER_FAILURE_REASON_/,"").replace(/_/g," ").toLowerCase():void 0;throw new D(e?.message||e?.error_details||n||r?.toString()||"Operation failed",400)}}var Vn=I(()=>{"use strict";g();l();pt()});var Oe,lr,kt,Hn=I(()=>{"use strict";g();l();Oe={MARKET:"market",LIMIT:"limit",STOP_LIMIT:"stop_limit"},lr={UP:"up",DOWN:"down"},kt={GTC:"GTC",IOC:"IOC",FOK:"FOK",GTD:"GTD"}});function Do(t,e){let r={...e},n=t;for(let[i,s]of Object.entries(r)){let o="{"+i+"}";s!=null&&n.includes(o)&&(n=n.replaceAll(o,encodeURIComponent(String(s))),delete r[i])}return{url:n,remaining:r}}async function at(t,e,r,n){let{url:i,remaining:s}=Do(r,n),o=e==="POST"||e==="PUT"||e==="DELETE"||e==="PATCH",a,c=null;if(o)a=t.baseURL+i,Object.keys(s).length>0&&(c=new TextEncoder().encode(JSON.stringify(s)));else{let u=Object.entries(s).filter(([,f])=>f!=null).flatMap(([f,O])=>(Array.isArray(O)?O:[O]).map(E=>encodeURIComponent(f)+"="+encodeURIComponent(String(E)))).join("&");a=t.baseURL+i+(u?"?"+u:"")}let d=await t.doRequest({method:e,url:a,body:c}),p=new TextDecoder().decode(d.body),_;try{_=JSON.parse(p)}catch{_=p}if(d.status>=400){let u=_,f=u?.error_response?.message??u?.error_response?.error_details??u?.message??u?.error_details??p.slice(0,200);throw new Zt(f,d.status,_)}return{status:d.status,data:_}}function jn(t,e){return at(t,"POST","/api/v3/brokerage/convert/quote",e)}function Kn(t,e){return at(t,"POST","/api/v3/brokerage/orders/edit",e)}function Yn(t,e){return at(t,"GET","/api/v3/brokerage/accounts",e)}function Qn(t,e){return at(t,"GET","/api/v3/brokerage/products/{product_id}/candles",e)}function Jn(t,e){return at(t,"GET","/api/v3/brokerage/products/{product_id}/ticker",e)}function pr(t,e){return at(t,"GET","/api/v3/brokerage/products",e)}function Xn(t,e){return at(t,"POST","/api/v3/brokerage/portfolios/move_funds",e)}function Zn(t,e){return at(t,"POST","/api/v3/brokerage/orders",e)}function ti(t,e){return at(t,"POST","/api/v3/brokerage/orders/preview",e)}var Zt,vt=I(()=>{"use strict";g();l();Zt=class extends Error{status;data;constructor(e,r,n){super(e),this.status=r,this.data=n}}});import{randomUUID as Lo}from"node:crypto";function ei(t){let e=t.type;if(e===Oe.MARKET)return{market_market_ioc:{...t.quote_size&&{quote_size:t.quote_size},...t.base_size&&{base_size:t.base_size}}};if(e===Oe.LIMIT){let r=t.time_in_force??kt.GTC,n={base_size:t.base_size,limit_price:t.limit_price,...t.post_only&&{post_only:!0}};return r===kt.IOC?{sor_limit_ioc:n}:r===kt.FOK?{limit_limit_fok:n}:r===kt.GTD?{limit_limit_gtd:{...n,...t.end_time&&{end_time:t.end_time}}}:{limit_limit_gtc:n}}else if(e===Oe.STOP_LIMIT){let r=t.stop_direction===lr.UP?"STOP_DIRECTION_STOP_UP":t.stop_direction===lr.DOWN?"STOP_DIRECTION_STOP_DOWN":(()=>{throw new D("stop_direction is required for stop_limit orders (up or down)",400)})(),n=t.time_in_force??kt.GTC,i={base_size:t.base_size,limit_price:t.limit_price,stop_price:t.stop_price,stop_direction:r};return n===kt.GTD?{stop_limit_stop_limit_gtd:{...i,...t.end_time&&{end_time:t.end_time}}}:{stop_limit_stop_limit_gtc:i}}throw new D(`Unknown order type: ${e}. Use market, limit, or stop_limit.`,400)}function Mo(t){let e={client_order_id:t.client_order_id??Lo(),product_id:t.product_id,side:t.side,order_configuration:ei(t)};return t.portfolio_id&&(e.retail_portfolio_id=t.portfolio_id),t.reduce_only&&(e.reduce_only=!0),e}var Fo,Uo,qo,ri,ni=I(()=>{"use strict";g();l();It();pt();Vn();Hn();Nt();vt();Fo=async(t,e)=>{let r=Mo(t),n=await Zn(e,r);return gr(n.data),n.data.success_response??n.data},Uo=async(t,e)=>{let r=await ti(e,{product_id:t.product_id,side:t.side,order_configuration:ei(t)}),n=r.data;if(n.errs?.length>0)throw new D(n.errs[0].replace(/^PREVIEW_/,"").replace(/_/g," ").toLowerCase(),400);return r.data},qo=async(t,e)=>{if(!t.base_size&&!t.limit_price)throw new D("Provide base_size and/or limit_price to edit",400);let r={order_id:t.order_id,size:t.base_size??"",price:t.limit_price??""},n=await Kn(e,r);return gr(n.data),{order_id:t.order_id,status:"EDITED"}},ri={orders_list:C(Mn,{requestMap:{status:"order_status",side:"order_side",start:"start_date",end:"end_date"}}),orders_get:C(Ln,{responseUnwrap:"order"}),orders_create:Fo,orders_preview:Uo,orders_edit:qo,orders_cancel:C(Tn),orders_close_position:C(Sn),orders_fills:C(Dn,{requestMap:{side:"order_side",start:"start_sequence_timestamp",end:"end_sequence_timestamp"}})}});function ii(t){return String(Math.floor(new Date(t).getTime()/1e3))}var Bo,zo,Wo,$o,Vo,Ho,si,oi=I(()=>{"use strict";g();l();It();pt();Nt();vt();Bo={"1m":"ONE_MINUTE","5m":"FIVE_MINUTE","15m":"FIFTEEN_MINUTE","30m":"THIRTY_MINUTE","1h":"ONE_HOUR","2h":"TWO_HOUR","4h":"FOUR_HOUR","6h":"SIX_HOUR","1d":"ONE_DAY"},zo={"1m":60,"5m":300,"15m":900,"30m":1800,"1h":3600,"2h":7200,"4h":14400,"6h":21600,"1d":86400},Wo=60,$o=async(t,e)=>{let{symbol:r,limit:n,cursor:i,...s}=t;if(r){let a=r.toUpperCase(),p=((await pr(e,s)).data.products??[]).filter(u=>u.base_currency_id===a||u.quote_currency_id===a),_=n!==void 0&&n>0?p.slice(0,n):p;return{products:_,num_products:_.length}}return(await pr(e,{...s,limit:n,cursor:i})).data};Vo=async(t,e)=>{if(!t.granularity)throw new D("granularity is required (expected execute() to apply its default)",500);let r=t.granularity,n=Bo[r],i=zo[r],s=Math.floor(Date.now()/1e3),o=t.end?ii(t.end):String(s),a=t.start?ii(t.start):String(Number(o)-Wo*i);return(await Qn(e,{...t,granularity:n,start:a,end:o})).data},Ho=async(t,e)=>{let r=t.limit??100;return(await Jn(e,{...t,limit:r})).data},si={products_list:$o,products_get:C(qn),products_ticker:Ho,products_book:C(Bn),products_candles:Vo,products_best_bid_ask:C(Nn)}});var jo,ai,ci=I(()=>{"use strict";g();l();It();Nt();vt();pt();jo=async(t,e)=>{let{from:r,to:n,...i}=t,s=await jn(e,{...i,from_account:r,to_account:n});if(!s.data?.trade?.id)throw new D(`Convert quote returned no trade for ${t.from} \u2192 ${t.to}. Verify balance, supported pair, and account eligibility.`,422);return s.data},ai={convert_quote:jo,convert_execute:C(xn,{requestMap:{quote_id:"trade_id",from:"from_account",to:"to_account"}}),convert_get:C(Gn,{requestMap:{quote_id:"trade_id",from:"from_account",to:"to_account"},responseUnwrap:"trade"})}});var Ko,_i,ui=I(()=>{"use strict";g();l();vt();Ko=async(t,e)=>{let r={};t.portfolio_id&&(r.retail_portfolio_id=t.portfolio_id),t.limit&&(r.limit=t.limit),t.cursor&&(r.cursor=t.cursor);let i=(await Yn(e,r)).data,s=i.accounts??[],o=t.show_zero?s:s.filter(a=>parseFloat(a.available_balance?.value??"0")!==0||parseFloat(a.hold?.value??"0")!==0);return{accounts:o,has_next:i.has_next,cursor:i.cursor,size:o.length}},_i={balance:Ko}});var Yo,di,gi=I(()=>{"use strict";g();l();pt();vt();Yo=async(t,e)=>{let r={funds:{value:t.amount,currency:t.currency},source_portfolio_uuid:t.from,target_portfolio_uuid:t.to},i=(await Xn(e,r)).data;if(!i?.source_portfolio_uuid)throw new D("Transfer failed \u2014 check amount, currency, and portfolio UUIDs",400);return i},di={transfer:Yo}});var li,pi=I(()=>{"use strict";g();l();It();Nt();li={fees:C(zn)}});var mi,fi=I(()=>{"use strict";g();l();mi={x402_resources:{endpoint:{origin:"AgentAPI_X402Resources",method:"GET",path:"/x402/resources"}},x402_pay:{endpoint:{origin:"AgentAPI_X402Pay",method:"POST",path:"/x402/pay"}},x402_fetch:{endpoint:{origin:"AgentAPI_X402Fetch",method:"POST",path:"/x402/fetch"}}}});function Re(t){return Qo[t]}var Qo,mr=I(()=>{"use strict";g();l();$n();ni();oi();ci();ui();gi();pi();fi();Qo={...Wn,...ri,...si,...ai,..._i,...di,...li,...mi}});function fr(t,e){if(!e)return t;let r={};for(let[n,i]of Object.entries(t)){let s=e[n]??n;r[s]=i}return r}function yi(t,e){if(!e||typeof t!="object"||t===null||Array.isArray(t))return t;let r={};for(let[n,i]of Object.entries(t)){let s=e[n]??n;r[s]=i}return r}var bi=I(()=>{"use strict";g();l()});function Jo(t,e){let r={...e},n=t;for(let[i,s]of Object.entries(e)){if(s==null||s==="")continue;let o=`{${i}}`;n.includes(o)&&(n=n.replaceAll(o,encodeURIComponent(String(s))),delete r[i])}return{resolvedPath:n,remainingParams:r}}function Xo(t){let e=[];for(let[r,n]of Object.entries(t))if(n!=null)if(Array.isArray(n))for(let i of n)e.push(`${encodeURIComponent(r)}=${encodeURIComponent(String(i))}`);else e.push(`${encodeURIComponent(r)}=${encodeURIComponent(String(n))}`);return e.length>0?"?"+e.join("&"):""}function Zo(t,e){if(!e)return t;let r={...t};for(let[n,i]of Object.entries(e)){let s=r[n];if(s!=null){if(i==="join-comma"&&Array.isArray(s))r[n]=s.join(",");else if(i==="split-comma"){let o=Array.isArray(s)?s:[s];r[n]=o.flatMap(a=>String(a).split(",").map(c=>c.trim()).filter(Boolean))}}}return r}function hi(t,e){return`${t.replace(/\/+$/,"")}${e}`}function ta(t){return t===408||t===429||t>=500}function ea(t){return t instanceof TypeError||t instanceof Error&&(t.name==="AbortError"||t.name==="TimeoutError")}function ra(t,e){if(t&&typeof t=="object"&&!Array.isArray(t)){let r=typeof t.hint=="string"&&t.hint?`${t.hint} `:"";return{...t,hint:`${r}${yr}`}}return{error:"AGENT_API_REQUEST_FAILED",code:e,message:typeof t=="string"&&t?t:`Agent API request failed with HTTP ${e}.`,hint:yr}}function Ei(t,e){return{status:400,data:{error:"REST_ENDPOINT_UNAVAILABLE",code:400,message:`${e} endpoint is not configured for environment "${t.envName}". Configure the endpoint for this environment before retrying.`}}}function na(t,e){let r=e.split("."),n=t;for(let i of r){if(n==null||typeof n!="object")return t;n=n[i]}return n!==void 0?n:t}function ia(t){return t&&typeof t=="object"&&("body"in t||"query"in t||"path"in t||"rawBody"in t)}function te(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(n=>te(n,e));let r={};for(let n of e.fields){if(!(n in t))continue;let i=e.nested?.[n];i&&Array.isArray(t[n])?r[n]=t[n].map(s=>te(s,i)):i&&typeof t[n]=="object"&&t[n]!==null?r[n]=te(t[n],i):r[n]=t[n]}return r}function sa(t,e){let r=br[t];if(!r)return;if(!e)return r;let n=r;for(let i of e.split(".")){let s=n?.nested?.[i];if(!s)return r;n=s}return n}async function Gt(t,e,r){let n=ia(e),i=n?e.body??{}:{},s=n?e.query??{}:{},o=n?e.path??{}:{},a=n?e.headers??{}:{},c=n?e.rawBody??null:null,d=!1,p=Re(t);if(!p)return{status:404,data:{error:"UNKNOWN_OPERATION",code:404,message:`No route for ${t}`}};let _=Ii.find(m=>m.id===t);if(!n)for(let[m,h]of Object.entries(e)){let A=_?.params.find(ut=>ut.name===m),S=A?.in==="query"?s:A?.in==="path"?o:i;S[m]=h}if(r.transport==="agent"&&!_?.agentApi)return{status:400,data:{error:"AGENT_API_ROUTE_UNAVAILABLE",code:400,message:`${t} is not available through the Agent API. Set COINBASE_TRANSPORT=brokerage to use direct brokerage.`}};let u=_?.agentApi?lt(r.env,r.envName):"",f=_?.agentApi==="only"||r.transport==="agent"||_?.agentApi==="eligible"&&r.transport!=="brokerage"&&!!u;if(_?.params){if(c)try{let m=JSON.parse(new TextDecoder().decode(c));m&&typeof m=="object"&&!Array.isArray(m)&&(d=!0,Object.assign(i,m))}catch{}for(let m of _.params){if(m.default===void 0||m.required||o[m.name]!==void 0||i[m.name]!==void 0||s[m.name]!==void 0)continue;let h=m.in==="query"?s:m.in==="path"?o:i;h[m.name]=m.default}{let m=_.params.filter(S=>(S.in==="body"||!dr(p)&&S.in==="path")&&S.required),h={...o,...i,...s},A=m.filter(S=>h[S.name]===void 0||h[S.name]==="");if(A.length>0)return{status:400,data:{error:"MISSING_FIELDS",code:400,message:`Missing required field(s): ${A.map(ut=>ut.name).join(", ")}`}}}{let m={...o,...i,...s},h={},A={};for(let S of _.params)if(S.oneOf&&(A[S.oneOf]||(A[S.oneOf]=[]),A[S.oneOf].push(S.name),m[S.name]!==void 0&&m[S.name]!=="")){if(h[S.oneOf])return{status:400,data:{error:"CONFLICTING_FIELDS",code:400,message:`${h[S.oneOf]} and ${S.name} are mutually exclusive. Provide one, not both.`}};h[S.oneOf]=S.name}for(let[S,ut]of Object.entries(A))if(!h[S])return{status:400,data:{error:"MISSING_FIELDS",code:400,message:`One of ${ut.join(", ")} is required.`}}}for(let m of _.params)for(let h of[i,s,o]){if(h[m.name]===void 0)continue;if(m.type==="array"&&typeof h[m.name]=="string"&&(h[m.name]=h[m.name].split(",").map(st=>st.trim()).filter(Boolean)),m.type==="boolean"){if(typeof h[m.name]!="boolean"&&(typeof h[m.name]!="string"||h[m.name]!=="true"&&h[m.name]!=="false"))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected "true" or "false".`}};typeof h[m.name]=="string"&&(h[m.name]=h[m.name]==="true")}else if((m.type==="integer"||m.type==="number")&&typeof h[m.name]=="string"){let st=Number(h[m.name]);if(!Number.isFinite(st))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected a number.`}};h[m.name]=st}if(m.enum&&!m.enum.includes(String(h[m.name])))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected one of: ${m.enum.join(", ")}`}};let A=m.pattern?ki.get(m.pattern):void 0,S=m.format?Rn[m.format]:void 0,ut=A??S;if(ut&&typeof h[m.name]=="string"){let st=h[m.name],Xr=m.format?Pn[m.format]:void 0;if(!(ut.test(st)&&(!A||!S||S.test(st))&&(!Xr||Xr(st)))){let Zr=(m.description??"").split(/\.\s/)[0].replace(/\.?\s*$/,""),oo=Zr?`. ${Zr}.`:".";return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${String(st).slice(0,80)}"${oo}`}}}}}}if(!f&&!r.baseURL)return Ei(r,"Brokerage API");if(!f&&!dr(p)){let m={...i,...s,...o};try{let h=await p(m,r),A=br[t];return A&&(h=te(h,A)),{status:200,data:h}}catch(h){if(h instanceof Zt)return{status:h.status,data:h.data};let A=h instanceof D?h.status:500,S=D.stripGrpcPrefix(h instanceof Error?h.message:String(h));return{status:A,data:{error:"HANDLER_ERROR",code:A,message:S}}}}let O=p,E=f?{origin:"AgentAPI",method:_.method,path:_.agentPath??_.path}:O.endpoint,x=f?void 0:O.requestMap,w=f?void 0:O.responseMap,G=f?void 0:O.responseUnwrap,F={...i,...o},Y=fr(F,x),{resolvedPath:R,remainingParams:P}=Jo(E.path,Y);if(R.includes("{"))return{status:400,data:{error:"MISSING_PATH_PARAMS",code:400,message:`Missing required param(s): ${(R.match(/\{([^}]+)\}/g)?.map(h=>h.slice(1,-1))??[]).join(", ")}`}};let H=E.method==="POST"||E.method==="PUT"||E.method==="DELETE"||E.method==="PATCH",V,Q=c??null,ue={...f?Zo(s,_.agentQueryTransforms):fr(s,x)},k=f?u:E.baseURL??r.baseURL;if(!k)return Ei(r,f?"Agent API":"Brokerage API");if(H){V=hi(k,R);let m=f&&Object.keys(o).some(h=>Object.hasOwn(P,h));c&&d&&m?Q=new TextEncoder().encode(JSON.stringify(P)):!Q&&Object.keys(P).length>0&&(Q=new TextEncoder().encode(JSON.stringify(P)))}else Object.assign(ue,P),V=hi(k,R);let T=Xo(ue);T&&(V+=T);let v;try{v=await r.doRequest({method:E.method,url:V,body:Q,headers:Object.keys(a).length>0?a:void 0})}catch(m){if(!f||_?.agentApi!=="eligible"||!ea(m))throw m;let h=m instanceof Error?m.message:String(m);throw new Error(`${h}
|
|
48
|
-
Hint: ${
|
|
43
|
+
[Runtime.InteropServices.Marshal]::FreeHGlobal($blob)`,Rt(n))}delete(e,r){try{Xe(`[void][Win32.Cred]::CredDelete('${Ee(Je(e,r))}', 1, 0)`)}catch{}}}});function Kt(){if(dt!==void 0)return dt;try{process.platform==="darwin"?dt=new ye:process.platform==="linux"?dt=new he:process.platform==="win32"?dt=new Ie:dt=null}catch{_n||(process.stderr.write(`warning: OS keychain not accessible \u2014 secrets stored in keychain will not be available
|
|
44
|
+
`),_n=!0),dt=null}return dt}function un(t){let e=Kt();if(!e)return null;try{return e.get(It,t)}catch{return null}}function dn(t,e){let r=Kt();if(!r)return!1;try{return r.set(It,t,e),!0}catch{return!1}}function gn(t){let e=Kt();if(e)try{e.delete(It,t)}catch{}}function ln(){return Kt()!==null}function pn(){let t=Kt();if(!t)return!1;let e="__coinbase_cli_preflight__";try{t.set(It,e,"ok");let r=t.get(It,e);return t.delete(It,e),r==="ok"}catch{try{t.delete(It,e)}catch{}return!1}}var It,dt,_n,Ze=I(()=>{"use strict";g();l();sn();on();cn();It="coinbase-cli",_n=!1});var kn={};jt(kn,{activeEnvName:()=>wt,activeEnvironment:()=>Jt,authIsViable:()=>nr,builtinEnvironments:()=>X,clearEnvCredentialCache:()=>or,clearEnvironmentSecretsFromKeychain:()=>ir,clearHistory:()=>Xt,configDir:()=>gt,configPath:()=>nt,credentialsFor:()=>Qt,envCredential:()=>Yt,getHistory:()=>_r,historyEnabled:()=>Oe,hydrateEnvironmentSecrets:()=>In,isBuiltinURL:()=>ke,loadConfig:()=>J,resolveAgentAPIURLForEnvironment:()=>lt,resolveBrokerageURL:()=>Z,resolveURL:()=>Eo,saveConfig:()=>at,scrubbedEnv:()=>ar,setHistory:()=>cr,setLockOptions:()=>ko,withConfigLock:()=>sr,writeEnvironmentSecretsToKeychain:()=>vn});import{readFileSync as yn,writeFileSync as bn,mkdirSync as hn,renameSync as fo,unlinkSync as tr,openSync as yo,closeSync as bo,statSync as ho}from"node:fs";import{homedir as mn}from"node:os";import{join as ve}from"node:path";function gt(){if(process.env.COINBASE_CONFIG_DIR)return process.env.COINBASE_CONFIG_DIR;if(process.platform==="win32"){let t=process.env.APPDATA??ve(mn(),"AppData","Roaming");return ve(t,"coinbase")}return ve(mn(),".config","coinbase")}function nt(){return ve(gt(),"config.json")}function En(t){if(X[t])return X[t];let e=fn[t];if(e&&X[e])return X[e];let r={...X};for(let[i,s]of Object.entries(fn))X[s]&&(r[i]=X[s]);let n=Object.keys(r).find(i=>t.startsWith(i+"-"));return n?r[n]:void 0}function Z(t,e){return t.endpoints?.brokerageApi??t.url??En(e)?.brokerageApi??""}function Eo(t,e){return Z(t,e)}function lt(t,e){return t.endpoints?.agentApi??En(e)?.agentApi??""}function ke(t){return Object.values(X).some(e=>e.brokerageApi&&t.startsWith(e.brokerageApi))}function Io(t,e){return Object.values(xt[e].secrets).map(r=>r(t))}function nr(t){if(!t)return!1;let e=xt[t.type];return e?Object.keys(e.secrets).every(r=>!!t[r]):!1}function In(t,e){if(!e.auth)return e;let r=xt[e.auth.type];if(!r)return e;let n=e.auth,i={...n},s=!1,o=!1;for(let[a,c]of Object.entries(r.secrets)){if(n[a]){o=!0;continue}let d=un(c(t));d&&(i[a]=d,s=!0)}return nr(i)?{...e,auth:i,...o&&!s?{_plaintextBacked:!0}:{}}:{...e,auth:void 0}}function vn(t,e){if(!e.auth)return!0;if(!ln())return!1;let r=e.auth.type,n=xt[r];if(!n)return!0;if(!nr(e.auth)){let s=Object.keys(n.secrets).filter(o=>!e.auth[o]);throw new Error(`writeEnvironmentSecretsToKeychain: ${r} for "${t}" missing ${s.join(", ")}`)}let i=!0;for(let[s,o]of Object.entries(n.secrets))dn(o(t),e.auth[s])||(i=!1);return i}function ir(t){for(let e of Object.keys(xt))for(let r of Io(t,e))gn(r)}function Yt(t){return t.auth}function Qt(t,e){if(e.auth?.type==="cdp_key")return{keyId:e.auth.key_id,keySecret:e.auth.key_secret};throw new Error(`environment "${t}" has no credentials. Run: coinbase env ${t} --key-file path/to/key.json`)}function J(){let t={env:"",environments:{},history:{}};try{let e=yn(nt(),"utf8"),r=JSON.parse(e);t.env=r.env??"";let n=r.environments??{};for(let[i,s]of Object.entries(n))t.environments[i]=In(i,s);return t.history=r.history??{},r.settings&&(t.settings=r.settings),t}catch(e){if(e.code!=="ENOENT")throw e instanceof SyntaxError?new Error(`invalid config JSON: ${e.message}`):new Error(`reading config: ${e.message}`)}return t}function at(t,e={}){let r=gt();hn(r,{recursive:!0,mode:448});let n={},i=[];for(let[c,d]of Object.entries(t.environments)){let p={};if(d.url!==void 0&&(p.url=d.url),d.endpoints!==void 0&&(p.endpoints={...d.endpoints}),!d.auth){n[c]=p;continue}let _=vn(c,d),u=e.allowPlaintext===!0||d._plaintextBacked===!0;if(!_){if(!u){i.push(c);continue}p.auth=d.auth,n[c]=p;continue}let f=xt[d.auth.type];f&&(p.auth=f.metadataOnly(d.auth)),n[c]=p}if(i.length)throw new Error(`OS keychain unavailable; refusing to persist secrets for environment(s): ${i.join(", ")}.
|
|
45
|
+
Re-run the env-setup command with --allow-plaintext-secrets to write secrets to ${nt()} (file is mode 0600), or install/unlock your OS keychain (macOS Keychain, libsecret on Linux, Windows Credential Manager).`);let s={env:t.env,environments:n};Object.keys(t.history).length>0&&(s.history=t.history),t.settings&&(s.settings=t.settings);let o=nt(),a=`${o}.${process.pid}.${Date.now()}.tmp`;try{bn(a,JSON.stringify(s,null,2)+`
|
|
46
|
+
`,{mode:384}),fo(a,o)}catch(c){try{tr(a)}catch{}throw c}}function ko(t){Tt={...Tt,...t}}function St(){return nt()+vo}function Oo(t){let e=Date.now()+t;for(;Date.now()<e;);}function Ro(){try{let t=yo(St(),"wx",384);return bn(t,String(process.pid)),t}catch(t){if(t.code!=="EEXIST")throw t;return null}}function Po(){try{let t=ho(St());if(Date.now()-t.mtimeMs<Tt.staleAfterMs)return!1;let e=yn(St(),"utf8").trim(),r=Number(e);if(!Number.isInteger(r)||r<=0)return!0;try{return process.kill(r,0),!1}catch(n){return n.code==="ESRCH"}}catch{return!1}}function sr(t){hn(gt(),{recursive:!0,mode:448});let e=null;for(let r=0;r<Tt.retries&&(e=Ro(),e===null);r++){if(Po()){try{tr(St())}catch{}continue}Oo(Tt.baseDelayMs*(1+Math.random()))}if(e===null)throw new Error(`could not acquire config lock after ${Tt.retries} attempts: ${St()}`);try{return t()}finally{try{bo(e)}catch{}try{tr(St())}catch{}}}function or(){er=void 0,rr=void 0}function To(){return process.env.COINBASE_KEY_ID&&(er=process.env.COINBASE_KEY_ID,delete process.env.COINBASE_KEY_ID),process.env.COINBASE_KEY_SECRET&&(rr=process.env.COINBASE_KEY_SECRET,delete process.env.COINBASE_KEY_SECRET),{keyId:er,keySecret:rr}}function wt(t,e){return e||process.env.COINBASE_ENV||t.env}function Jt(t,e){let r=wt(t,e);if(!r)throw new Error("no environment configured. Run: coinbase env <name>");let n={...t.environments[r]},{keyId:i,keySecret:s}=To();if(i||s){let c=n.auth?.type==="cdp_key"?n.auth:void 0,d=i??c?.key_id??"",p=s??c?.key_secret??"";d&&p&&(n.auth={type:"cdp_key",key_id:d,key_secret:p})}if(process.env.COINBASE_URL){let c=process.env.COINBASE_URL;n.endpoints={...n.endpoints,brokerageApi:c},n.url=c,ke(c)||process.stderr.write(`warning: COINBASE_URL overrides to non-standard endpoint: ${c}
|
|
47
|
+
`)}let o=Z(n,r),a=lt(n,r);if(!o&&!a)throw new Error(`no REST endpoint for environment "${r}". Set a brokerage URL, an Agent API URL, or use a built-in environment name`);if(!n.auth)throw new Error(`no credentials for "${r}". Run: coinbase env ${r} --key-file path/to/key.json`);return{name:r,env:n}}function ar(){let t={...process.env};for(let e of So)delete t[e];return t}function Oe(t){return process.env.COINBASE_NO_HISTORY?!1:t.settings?.history?.enabled!==!1}function cr(t,e,r,n){t.history[e]||(t.history[e]={}),t.history[e][r]={last_used:new Date().toISOString(),values:n}}function _r(t,e,r){return t.history[e]?.[r]}function Xt(t,e,r){if(e&&r)return t.history[e]?.[r]?(delete t.history[e][r],Object.keys(t.history[e]).length===0&&delete t.history[e],1):0;if(e){let i=Object.keys(t.history[e]??{}).length;return delete t.history[e],i}let n=Object.values(t.history).reduce((i,s)=>i+Object.keys(s).length,0);return t.history={},n}var X,fn,xt,vo,Tt,er,rr,So,tt=I(()=>{"use strict";g();l();le();Ze();X=rn,fn=nn;xt={cdp_key:{secrets:{key_secret:t=>`${t}:cdp:key_secret`},metadataOnly:t=>({type:"cdp_key",key_id:t.key_id})}};vo=".lock",Tt={retries:50,baseDelayMs:20,staleAfterMs:5e3};So=["COINBASE_KEY_SECRET","COINBASE_KEY_ID"]});function Do(t,e,r){let n=new Date(Date.UTC(t,e-1,r));return n.getUTCFullYear()===t&&n.getUTCMonth()===e-1&&n.getUTCDate()===r}var et,rt,Rn,Pn,Tn,Ct=I(()=>{"use strict";g();l();et=[{name:"convert",actions:[{id:"convert_quote",name:"quote",method:"POST",path:"/convert/quote",summary:"Get Convert Quote",description:"Quotes a currency conversion (e.g. stablecoin pairs), returning rate, fees, and a quote id. Read-only preview \u2014 pass the id to convert_execute to commit; quotes expire, so execute promptly.",pathParams:[],params:[{name:"from",in:"body",type:"string",required:!0,description:"Source currency",example:"USDC"},{name:"to",in:"body",type:"string",required:!0,description:"Target currency",example:"USD"},{name:"amount",in:"body",type:"string",required:!0,description:"Amount to convert",example:"100.00"}],streamable:!1,watchFields:null,template:{from:"USDC",to:"USD",amount:"100.00"},responseFields:{fields:["trade"],nested:{trade:{fields:["id","status","amount","subtotal","total","total_fee","exchange_rate","source_currency","target_currency"]}}}},{id:"convert_execute",name:"execute",method:"POST",path:"/convert/execute/{quote_id}",summary:"Execute Convert Trade",description:"Executes a previously quoted conversion using the quote id from convert_quote. This moves funds at the quoted rate \u2014 always get a fresh quote first, since quotes expire. The from/to currencies must match the original quote.",pathParams:["quote_id"],params:[{name:"quote_id",in:"path",type:"string",required:!0,description:"Quote ID from convert quote response"},{name:"from",in:"body",type:"string",required:!0,description:"Source currency",example:"USDC"},{name:"to",in:"body",type:"string",required:!0,description:"Target currency",example:"USD"}],streamable:!1,watchFields:null,template:{from:"USDC",to:"USD"},responseFields:{fields:["trade"],nested:{trade:{fields:["id","status"]}}}},{id:"convert_get",name:"get",method:"GET",path:"/convert/get/{quote_id}",summary:"Get Convert Status",description:"Check status of a conversion by quote ID.",pathParams:["quote_id"],params:[{name:"quote_id",in:"path",type:"string",required:!0,description:"Quote ID"},{name:"from",in:"query",type:"string",required:!0,description:"Source currency"},{name:"to",in:"query",type:"string",required:!0,description:"Target currency"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["id","status","source_currency","target_currency","exchange_rate"]}}]},{name:"orders",actions:[{id:"orders_list",name:"list",method:"GET",path:"/orders",summary:"List Orders",description:"Lists orders with optional filters by status, product, side, and time range. Read-only. Use status=OPEN to find resting orders that can be edited or cancelled.",pathParams:[],params:[{name:"status",in:"query",type:"string",required:!1,description:"Filter by status"},{name:"product_ids",in:"query",type:"array",required:!1,description:"Filter by product (e.g. BTC-USD). Comma-separated for multiple."},{name:"side",in:"query",type:"string",required:!1,description:"Filter by side",enum:["BUY","SELL"]},{name:"product_type",in:"query",type:"string",required:!1,description:"Filter by product type",enum:["SPOT","FUTURE"]},{name:"start",in:"query",type:"string",required:!1,description:"Start date (RFC 3339 with timezone, e.g. 2024-01-01T00:00:00Z)",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End date (RFC 3339 with timezone, e.g. 2024-12-31T23:59:59Z)",format:"date-time"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!0,watchFields:{status:{type:"string",enum:["PENDING","OPEN","FILLED","CANCELLED","FAILED","EXPIRED","CANCEL_QUEUED"],description:"Order status"},side:{type:"string",enum:["BUY","SELL"],description:"Order side"},price:{type:"number",description:"Average filled price"},filled_size:{type:"number",description:"Filled quantity"},fees:{type:"number",description:"Total fees"},product_id:{type:"string",description:"Trading pair"},order_id:{type:"string",description:"Order ID"}},template:{},responseFields:{fields:["orders","has_next","cursor"],nested:{orders:{fields:["order_id","product_id","side","status","order_configuration","created_time","completion_percentage","filled_size","average_filled_price","total_fees","total_value_after_fees","number_of_fills"]}}},agentApi:"eligible",agentQueryTransforms:{product_ids:"join-comma"}},{id:"orders_create",name:"create",method:"POST",path:"/orders",summary:"Create Order",description:"Places a live order \u2014 executes immediately and moves funds (market buy spends quote currency; sell disposes of base). Preview with orders_preview first to estimate fees, fill price, and slippage. A FUTURE order rejected on eligibility grounds means the account isn't approved for futures. Send the user to https://help.coinbase.com/en/coinbase/trading-and-funding/derivatives/futures-intro to apply.",pathParams:[],params:[{name:"product_id",in:"body",type:"string",required:!0,description:"Trading pair (BASE-QUOTE). Use the quote currency the user names (e.g. USDC); never default to USD. If unspecified, check balance; prefer USDC if both held. Tell the user if the pair is unavailable.",example:"BASE-QUOTE"},{name:"side",in:"body",type:"string",required:!0,description:"BUY or SELL",enum:["BUY","SELL"],example:"BUY"},{name:"type",in:"body",type:"string",required:!0,description:"market = fill now; limit = fill at price or better; stop_limit = limit triggered at stop_price",enum:["market","limit","stop_limit"],example:"market"},{name:"quote_size",in:"body",type:"string",required:!1,description:"Quote currency amount (e.g. spend $100 USD). Market buy only. Mutually exclusive with base_size.",oneOf:"base_size|quote_size",example:"100.00"},{name:"base_size",in:"body",type:"string",required:!1,description:"Base currency amount (e.g. buy 0.001 BTC). Any side/type.",oneOf:"base_size|quote_size",example:"0.001"},{name:"limit_price",in:"body",type:"string",required:!1,description:"Limit price (limit/stop_limit orders)",example:"65000.00"},{name:"stop_price",in:"body",type:"string",required:!1,description:"Stop price (stop_limit orders)",example:"60000.00"},{name:"stop_direction",in:"body",type:"string",required:!1,description:"up = trigger when price rises above stop_price. down = trigger when falls below.",enum:["up","down"],example:"down"},{name:"post_only",in:"body",type:"boolean",required:!1,description:"Post-only mode (limit orders). Rejects if would take liquidity."},{name:"time_in_force",in:"body",type:"string",required:!1,description:"GTC=good til cancelled. IOC=immediate or cancel. FOK=fill or kill.",enum:["GTC","IOC","FOK","GTD"],example:"GTC"},{name:"end_time",in:"body",type:"string",required:!1,description:"Expiry time for GTD orders (RFC 3339). Required when time_in_force=GTD.",format:"date-time",example:"2024-12-31T23:59:59Z"},{name:"reduce_only",in:"body",type:"boolean",required:!1,description:"Only reduce existing position. Rejects if would increase exposure."},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Scopes the order to a specific portfolio (defaults to auth-scoped portfolio)"},{name:"client_order_id",in:"body",type:"string",required:!1,description:"Idempotency key (auto-generated if omitted)"}],streamable:!1,watchFields:null,template:{product_id:"BASE-QUOTE",side:"BUY",type:"market",quote_size:"100.00",base_size:"0.001",limit_price:"65000.00",stop_price:"60000.00",stop_direction:"up",post_only:!1,time_in_force:"GTC",end_time:"2024-12-31T23:59:59Z",reduce_only:!1,portfolio_id:"<string>",client_order_id:"<string>"},responseFields:{fields:["order_id","product_id","side","client_order_id"]},agentApi:"eligible"},{id:"orders_preview",name:"preview",method:"POST",path:"/orders/preview",summary:"Preview Order",description:"Estimate fees, fill price, and slippage without executing. A FUTURE preview rejected on eligibility grounds means the account isn't approved for futures. Send the user to https://help.coinbase.com/en/coinbase/trading-and-funding/derivatives/futures-intro to apply.",pathParams:[],params:[{name:"product_id",in:"body",type:"string",required:!0,description:"Trading pair (BASE-QUOTE). Use the quote currency the user names (e.g. USDC); never default to USD. If unspecified, check balance; prefer USDC if both held. Tell the user if the pair is unavailable.",example:"BASE-QUOTE"},{name:"side",in:"body",type:"string",required:!0,description:"BUY or SELL",enum:["BUY","SELL"],example:"BUY"},{name:"type",in:"body",type:"string",required:!0,description:"market = fill now; limit = fill at price or better; stop_limit = limit triggered at stop_price",enum:["market","limit","stop_limit"],example:"market"},{name:"quote_size",in:"body",type:"string",required:!1,description:"Quote currency amount (e.g. spend $100 USD). Mutually exclusive with base_size.",oneOf:"base_size|quote_size",example:"100.00"},{name:"base_size",in:"body",type:"string",required:!1,description:"Base currency amount (e.g. 0.001 BTC). Mutually exclusive with quote_size.",oneOf:"base_size|quote_size",example:"0.001"},{name:"limit_price",in:"body",type:"string",required:!1,description:"Limit price (for limit/stop_limit previews)",example:"65000.00"},{name:"stop_price",in:"body",type:"string",required:!1,description:"Stop price (for stop_limit previews)",example:"60000.00"},{name:"stop_direction",in:"body",type:"string",required:!1,description:"up = trigger when price rises above stop_price. down = trigger when falls below.",enum:["up","down"],example:"down"}],streamable:!1,watchFields:null,template:{product_id:"BASE-QUOTE",side:"BUY",type:"market",quote_size:"100.00",base_size:"0.001",limit_price:"65000.00",stop_price:"60000.00",stop_direction:"up"},responseFields:{fields:["order_total","commission_total","slippage","est_average_filled_price","base_size","quote_size","best_bid","best_ask","long_leverage","short_leverage","max_leverage","position_notional_limit","available_buying_power","predicted_liquidation_price"]},agentApi:"eligible"},{id:"orders_edit",name:"edit",method:"POST",path:"/orders/edit/{order_id}",summary:"Edit Order",description:"Atomically update an open order's price or size without cancelling. Avoids the cancel+replace exposure window.",pathParams:["order_id"],params:[{name:"order_id",in:"path",type:"string",required:!0,description:"Order to edit"},{name:"base_size",in:"body",type:"string",required:!1,description:"New base size",example:"0.002"},{name:"limit_price",in:"body",type:"string",required:!1,description:"New limit price",example:"64000.00"}],streamable:!1,watchFields:null,template:{base_size:"0.002",limit_price:"64000.00"},responseFields:{fields:["order_id","status"]},agentApi:"eligible",agentPath:"/orders/edit"},{id:"orders_get",name:"get",method:"GET",path:"/orders/{order_id}",summary:"Get Order",description:"Retrieves the full status and fill details of a single order by ID. Read-only. Use after creating an order to confirm execution.",pathParams:["order_id"],params:[{name:"order_id",in:"path",type:"string",required:!0,description:"Order ID"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["order_id","product_id","side","status","order_configuration","created_time","completion_percentage","filled_size","average_filled_price","total_fees","total_value_after_fees","number_of_fills"]},agentApi:"eligible"},{id:"orders_cancel",name:"cancel",method:"POST",path:"/orders/cancel",summary:"Cancel Orders",description:"Cancels one or more open orders by ID. Removes resting orders from the book so reserved funds are released; already-filled portions are unaffected. Returns per-order success so a partial batch can fail.",pathParams:[],params:[{name:"order_ids",in:"body",type:"array",required:!0,description:"Order IDs to cancel"}],streamable:!1,watchFields:null,template:{order_ids:[]},responseFields:{fields:["results"],nested:{results:{fields:["success","order_id"]}}},agentApi:"eligible"},{id:"orders_close_position",name:"close-position",method:"POST",path:"/orders/close-position",summary:"Close Position",description:"Places a market order to flatten an open position for a product, moving funds immediately. Omit size for a full close or set it for a partial close. Preview the equivalent order first if fee or slippage impact matters.",pathParams:[],params:[{name:"client_order_id",in:"body",type:"string",required:!0,description:"Idempotency key"},{name:"product_id",in:"body",type:"string",required:!0,description:"Product to close",example:"BTC-PERP"},{name:"size",in:"body",type:"string",required:!1,description:"Partial close size (omit for full close)",example:"0.001"}],streamable:!1,watchFields:null,template:{client_order_id:"<string>",product_id:"BTC-PERP",size:"0.001"},responseFields:null,agentApi:"eligible"},{id:"orders_fills",name:"fills",method:"GET",path:"/orders/fills",summary:"List Fills",description:"Lists individual trade executions (fills) with commissions and maker/taker indicator, filterable by product, order, side, and time range. Read-only. Use this to reconcile actual fill prices and fees paid.",pathParams:[],params:[{name:"product_ids",in:"query",type:"array",required:!1,description:"Filter by product (e.g. BTC-USD)"},{name:"order_ids",in:"query",type:"string",required:!1,description:"Filter by order ID"},{name:"start",in:"query",type:"string",required:!1,description:"Start time (RFC 3339 with timezone, e.g. 2024-01-01T00:00:00Z)",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End time (RFC 3339 with timezone, e.g. 2024-12-31T23:59:59Z)",format:"date-time"},{name:"side",in:"query",type:"string",required:!1,description:"Filter by side",enum:["BUY","SELL"]},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["fills","cursor"],nested:{fills:{fields:["trade_id","order_id","trade_time","price","size","commission","product_id","side","liquidity_indicator"]}}},agentApi:"eligible",agentQueryTransforms:{product_ids:"join-comma",order_ids:"split-comma"}}]},{name:"portfolios",actions:[{id:"portfolios_list",name:"list",method:"GET",path:"/portfolios",summary:"List Portfolios",description:"Lists all portfolios on the account, including their UUIDs and types. Read-only. Use this to find the portfolio_id needed for orders, transfers, and balance queries.",pathParams:[],params:[{name:"portfolio_type",in:"query",type:"string",required:!1,description:"Filter by type (DEFAULT, CONSUMER)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["portfolios"],nested:{portfolios:{fields:["uuid","name","type","deleted"]}}}},{id:"portfolios_create",name:"create",method:"POST",path:"/portfolios",summary:"Create Portfolio",description:"Creates a new named portfolio for segregating funds and positions. Does not move any funds; use transfer afterward to fund it.",pathParams:[],params:[{name:"name",in:"body",type:"string",required:!0,description:"Portfolio name",example:"agent-1"}],streamable:!1,watchFields:null,template:{name:"agent-1"},responseFields:{fields:["uuid","name","type","deleted"]}},{id:"portfolios_get",name:"get",method:"GET",path:"/portfolios/{portfolio_id}",summary:"Get Portfolio Breakdown",description:"Returns portfolio metadata, balances, and positions.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"},{name:"currency",in:"query",type:"string",required:!1,description:"Currency for balance denomination"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["portfolio","portfolio_balances","spot_positions","futures_positions"],nested:{portfolio:{fields:["uuid","name","type","deleted"]},portfolio_balances:{fields:["total_balance","total_crypto_balance","total_cash_equivalent_balance"],nested:{total_balance:{fields:["value","currency"]},total_crypto_balance:{fields:["value","currency"]},total_cash_equivalent_balance:{fields:["value","currency"]}}},spot_positions:{fields:["asset","account_uuid","total_balance_fiat","total_balance_crypto","available_to_trade_fiat","allocation","is_cash"]},futures_positions:{fields:["product_id","contract_size","side","amount","avg_entry_price","current_price","unrealized_pnl","expiry","underlying_asset","product_name","venue","notional_value"]}}},agentApi:"eligible"},{id:"portfolios_edit",name:"edit",method:"PUT",path:"/portfolios/{portfolio_id}",summary:"Edit Portfolio",description:"Renames an existing portfolio. Metadata-only change; does not affect balances or positions.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"},{name:"name",in:"body",type:"string",required:!1,description:"New portfolio name"}],streamable:!1,watchFields:null,template:{name:"<string>"},responseFields:{fields:["uuid","name","type","deleted"]}},{id:"portfolios_delete",name:"delete",method:"DELETE",path:"/portfolios/{portfolio_id}",summary:"Delete Portfolio",description:"Permanently deletes a portfolio. The portfolio must be empty first \u2014 transfer out any remaining funds and close all positions before deleting. The DEFAULT portfolio cannot be deleted.",pathParams:["portfolio_id"],params:[{name:"portfolio_id",in:"path",type:"string",required:!0,description:"Portfolio UUID"}],streamable:!1,watchFields:null,template:{},responseFields:null}]},{name:"products",actions:[{id:"products_list",name:"list",method:"GET",path:"/products",summary:"List Products",description:"Lists tradable products and their current price and 24h stats, optionally filtered by symbol or type. Read-only. Use to discover valid product_id values before placing orders. Viewing products, including FUTURE ones, doesn't require any special account approval \u2014 trading them is a separate matter (see the product_type field description).",pathParams:[],params:[{name:"symbol",in:"query",type:"string",required:!1,description:"Filter products by symbol, matches base or quote side (e.g. USD, BTC). For a specific product use `get` (e.g. BTC-USD). Pagination ignored when set.",pattern:"^[A-Za-z0-9]+$"},{name:"product_type",in:"query",type:"string",required:!1,description:"Product type filter",enum:["SPOT","FUTURE"]},{name:"product_ids",in:"query",type:"array",required:!1,description:"Comma-separated product IDs"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["products","cursor","has_next","num_products"],nested:{products:{fields:["product_id","price","price_percentage_change_24h","volume_24h","product_type","quote_currency_id","base_currency_id","base_increment","quote_increment","base_min_size","base_max_size","quote_min_size","quote_max_size","status","future_product_details"],nested:{future_product_details:{fields:["contract_expiry_type"]}}}}},agentApi:"eligible",agentQueryTransforms:{product_ids:"join-comma"}},{id:"products_get",name:"get",method:"GET",path:"/products/{product_id}",summary:"Get Product",description:"Returns full details for a single product, including price and trading increments/min sizes. Read-only. Use base_increment and base_min_size to size orders that the exchange will accept. Viewing a product, including a FUTURE one, doesn't require any special account approval \u2014 trading it is a separate matter (see the product_type field description).",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Product ID (e.g. BTC-USD)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["product_id","price","price_percentage_change_24h","volume_24h","product_type","quote_currency_id","base_currency_id","base_increment","quote_increment","base_min_size","base_max_size","quote_min_size","quote_max_size","status","future_product_details"],nested:{future_product_details:{fields:["contract_expiry_type"]}}},agentApi:"eligible"},{id:"products_ticker",name:"ticker",method:"GET",path:"/products/{product_id}/ticker",summary:"Get Ticker",description:"Returns recent trades plus the current best bid and ask for a product. Read-only. Use for a quick spot price snapshot before previewing or placing an order.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Trading pair (e.g. BTC-USD)"},{name:"limit",in:"query",type:"integer",required:!1,description:"Number of trades. Defaults to 100."}],streamable:!0,watchFields:{price:{type:"number",description:"Last trade price"},bid:{type:"number",description:"Best bid"},ask:{type:"number",description:"Best ask"},bid_size:{type:"number",description:"Size at best bid"},ask_size:{type:"number",description:"Size at best ask"},volume:{type:"number",description:"24h volume"},high:{type:"number",description:"24h high"},low:{type:"number",description:"24h low"},pct_24h:{type:"number",description:"24h price change %"},product_id:{type:"string",description:"Trading pair"}},template:{},responseFields:{fields:["trades","best_bid","best_ask"],nested:{trades:{fields:["trade_id","product_id","price","size","time","side"]}}},agentApi:"eligible"},{id:"products_book",name:"book",method:"GET",path:"/products/{product_id}/book",summary:"Get Order Book",description:"Returns the bid/ask order book (price levels and sizes) for a product. Read-only. Use to gauge available liquidity and likely slippage before sizing a market order.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Product ID"},{name:"limit",in:"query",type:"integer",required:!1,description:"Number of levels"}],streamable:!0,watchFields:{spread:{type:"number",description:"Bid-ask spread"},mid:{type:"number",description:"Midpoint price"},product_id:{type:"string",description:"Trading pair"}},template:{},responseFields:{fields:["pricebook"],nested:{pricebook:{fields:["product_id","bids","asks","time"],nested:{bids:{fields:["price","size"]},asks:{fields:["price","size"]}}}}},agentApi:"eligible"},{id:"products_candles",name:"candles",method:"GET",path:"/products/{product_id}/candles",summary:"Get Candles",description:"Returns historical OHLCV candles for a product at a chosen granularity and time range. Read-only. Use for price history and technical analysis.",pathParams:["product_id"],params:[{name:"product_id",in:"path",type:"string",required:!0,description:"Trading pair (e.g. BTC-USD)"},{name:"start",in:"query",type:"string",required:!1,description:"Start time (RFC 3339, e.g. 2024-01-01T00:00:00Z). Defaults to 60 candles before end.",format:"date-time"},{name:"end",in:"query",type:"string",required:!1,description:"End time (RFC 3339, e.g. 2024-01-01T00:00:00Z). Defaults to now.",format:"date-time"},{name:"granularity",in:"query",type:"string",required:!1,description:"Candle interval: 1m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 1d. Defaults to 1h.",enum:["1m","5m","15m","30m","1h","2h","4h","6h","1d"],default:"1h"},{name:"limit",in:"query",type:"integer",required:!1,description:"Max candles"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["candles"],nested:{candles:{fields:["start","low","high","open","close","volume"]}}},agentApi:"eligible"},{id:"products_best_bid_ask",name:"best-bid-ask",method:"GET",path:"/products/best-bid-ask",summary:"Best Bid/Ask for Multiple Products",description:"Returns best bid and ask for one or more products in a single call.",pathParams:[],params:[{name:"product_ids",in:"query",type:"array",required:!1,description:"Comma-separated product IDs (e.g. BTC-USD,ETH-USD)"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["pricebooks"],nested:{pricebooks:{fields:["product_id","bids","asks","time"],nested:{bids:{fields:["price","size"]},asks:{fields:["price","size"]}}}}}}]},{name:"x402",actions:[{id:"x402_resources",name:"resources",method:"GET",path:"/x402/resources",summary:"Discover x402 Resources",description:"Discover curated x402-enabled resources. Discovery does not spend funds; use the returned payment requirements as budget hints and the input schema to call a resource.",pathParams:[],params:[{name:"q",in:"query",type:"string",required:!1,description:"Optional keyword filter over resource descriptions, providers, and tags"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["resources"],nested:{resources:{fields:["resource","description","accepts","inputSchema","outputSchema"],nested:{accepts:{fields:["amount"]}}}}},agentApi:"only"},{id:"x402_pay",name:"pay",method:"POST",path:"/x402/pay",summary:"Pay an x402 Payment Requirement",description:"Creates a ready-to-send x402 payment header by placing a USDC hold. This moves funds; use the smallest amount that satisfies the requirement and reuse idempotency_key only when retrying the same payment.",pathParams:[],params:[{name:"scheme",in:"body",type:"string",required:!0,description:"x402 payment scheme (currently exact)"},{name:"network",in:"body",type:"string",required:!0,description:"CAIP-2 network (currently eip155:8453)"},{name:"asset",in:"body",type:"string",required:!0,description:"USDC asset contract address"},{name:"pay_to",in:"body",type:"string",required:!0,description:"Recipient address"},{name:"amount",in:"body",type:"string",required:!0,description:"Required atomic-unit amount from the x402 challenge"},{name:"max_amount",in:"body",type:"string",required:!0,description:"Caller spend cap in atomic units"},{name:"max_timeout_seconds",in:"body",type:"integer",required:!0,description:"Authorization validity window in seconds"},{name:"x402_version",in:"body",type:"integer",required:!1,description:"x402 protocol version; defaults to 2",default:2},{name:"extra",in:"body",type:"object",required:!1,description:"EIP-712 domain; required by protocol semantics for x402_version 2"},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Optional portfolio UUID to pay from"},{name:"account_id",in:"body",type:"string",required:!1,description:"Optional USDC account UUID to debit"},{name:"idempotency_key",in:"body",type:"string",required:!1,description:"Reuse only to retry the same logical payment"}],streamable:!1,watchFields:null,template:{scheme:"<string>",network:"<string>",asset:"<string>",pay_to:"<string>",amount:"<string>",max_amount:"<string>",max_timeout_seconds:0,x402_version:2,extra:{name:"<string>",version:"<string>"},portfolio_id:"<string>",account_id:"<string>",idempotency_key:"<string>"},responseFields:{fields:["payment_header","payment_id","idempotency_key","expires_at"]},history:"disabled",agentApi:"only"},{id:"x402_fetch",name:"fetch",method:"POST",path:"/x402/fetch",summary:"Pay For and Fetch x402 Resource",description:"Fetches a resource returned by x402 resources. On a 402 challenge, the Agent API pays from custodial USDC and retries automatically. Only catalog URLs and catalog-declared input fields are accepted; input is sent as query parameters for GET resources and as JSON for POST resources. Protocol v2 only. max_amount optionally tightens the catalog advisory ceiling, which is enforced when omitted.",pathParams:[],params:[{name:"resource",in:"body",type:"string",required:!0,description:"Exact URL returned by x402 resources"},{name:"input",in:"body",type:"object",required:!1,description:"Request parameters validated against the resource catalog schema"},{name:"max_amount",in:"body",type:"string",required:!1,description:"Optional caller cap; catalog advisory ceiling applies when omitted"},{name:"portfolio_id",in:"body",type:"string",required:!1,description:"Optional portfolio UUID to pay from"},{name:"account_id",in:"body",type:"string",required:!1,description:"Optional USDC account UUID to debit"},{name:"idempotency_key",in:"body",type:"string",required:!1,description:"Reuse only to retry the same logical fetch"}],streamable:!1,watchFields:null,template:{resource:"<string>",input:{},max_amount:"<string>",portfolio_id:"<string>",account_id:"<string>",idempotency_key:"<string>"},responseFields:{fields:["data","paid","payment_id","idempotency_key","expires_at"]},history:"disabled",agentApi:"only"}]}],rt={balance:{id:"balance",name:"balance",method:"GET",path:"/balance",summary:"View Balances",description:"Lists account balances across currencies, showing available funds and amounts on hold. Read-only. Use before trading or transferring to confirm available funds; available_balance excludes funds held by open orders.",pathParams:[],params:[{name:"portfolio_id",in:"query",type:"string",required:!1,description:"Filter by portfolio"},{name:"show_zero",in:"query",type:"boolean",required:!1,description:"Include zero-balance accounts (default false)"},{name:"limit",in:"query",type:"integer",required:!1,description:"Results per page"},{name:"cursor",in:"query",type:"string",required:!1,description:"Pagination cursor"}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["accounts","has_next","cursor","size"],nested:{accounts:{fields:["uuid","name","currency","available_balance","hold","type","active","ready"],nested:{available_balance:{fields:["value","currency"]},hold:{fields:["value","currency"]}}}}}},transfer:{id:"transfer",name:"transfer",method:"POST",path:"/transfer",summary:"Move Funds Between Portfolios",description:"Moves funds of a single currency from one portfolio to another. This executes immediately and moves money \u2014 verify the source has sufficient available balance first. Both portfolio UUIDs come from portfolios_list.",pathParams:[],params:[{name:"amount",in:"body",type:"string",required:!0,description:"Amount to transfer",example:"100.00"},{name:"currency",in:"body",type:"string",required:!0,description:"Currency",example:"USD"},{name:"from",in:"body",type:"string",required:!0,description:"Source portfolio UUID",example:"d17b3486-..."},{name:"to",in:"body",type:"string",required:!0,description:"Target portfolio UUID",example:"a44ef7a8-..."}],streamable:!1,watchFields:null,template:{amount:"100.00",currency:"USD",from:"d17b3486-...",to:"a44ef7a8-..."},responseFields:{fields:["source_portfolio_uuid","target_portfolio_uuid"]}},fees:{id:"fees",name:"fees",method:"GET",path:"/fees",summary:"Fee Tier and Volume",description:"Fee tier, maker/taker rates, and 30-day volume.",pathParams:[],params:[{name:"product_type",in:"query",type:"string",required:!1,description:"Filter by product type",enum:["SPOT","FUTURE"]}],streamable:!1,watchFields:null,template:{},responseFields:{fields:["total_fees","fee_tier","margin_rate","advanced_trade_only_volume","advanced_trade_only_fees","coinbase_pro_volume","coinbase_pro_fees","total_balance","has_cost_plus_commission"],nested:{fee_tier:{fields:["pricing_tier","taker_fee_rate","maker_fee_rate"]}}}}},Rn=new Set(["balance","transfer","fees"]),Pn={"date-time":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/};Tn={"date-time":t=>{let e=t.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/);if(!e)return!1;let[,r,n,i,s,o,a]=e;return Do(+r,+n,+i)&&+s<24&&+o<60&&+a<61}}});function gr(t){return typeof t=="object"&&"endpoint"in t}function G(t,e){return{endpoint:t,...e}}var vt=I(()=>{"use strict";g();l()});var Sn,xn,wn,An,Cn,Nn,Gn,Dn,Ln,Mn,Fn,Un,qn,Bn,zn,Nt=I(()=>{"use strict";g();l();Sn={origin:"RetailBrokerageApi_CancelOrders",method:"POST",path:"/api/v3/brokerage/orders/batch_cancel"},xn={origin:"RetailBrokerageApi_ClosePosition",method:"POST",path:"/api/v3/brokerage/orders/close_position"},wn={origin:"RetailBrokerageApi_CommitConvertTrade",method:"POST",path:"/api/v3/brokerage/convert/trade/{trade_id}"},An={origin:"RetailBrokerageApi_CreatePortfolio",method:"POST",path:"/api/v3/brokerage/portfolios"},Cn={origin:"RetailBrokerageApi_DeletePortfolio",method:"DELETE",path:"/api/v3/brokerage/portfolios/{portfolio_uuid}"},Nn={origin:"RetailBrokerageApi_EditPortfolio",method:"PUT",path:"/api/v3/brokerage/portfolios/{portfolio_uuid}"},Gn={origin:"RetailBrokerageApi_GetBestBidAsk",method:"GET",path:"/api/v3/brokerage/best_bid_ask"},Dn={origin:"RetailBrokerageApi_GetConvertTrade",method:"GET",path:"/api/v3/brokerage/convert/trade/{trade_id}"},Ln={origin:"RetailBrokerageApi_GetFills",method:"GET",path:"/api/v3/brokerage/orders/historical/fills"},Mn={origin:"RetailBrokerageApi_GetHistoricalOrder",method:"GET",path:"/api/v3/brokerage/orders/historical/{order_id}"},Fn={origin:"RetailBrokerageApi_GetHistoricalOrders",method:"GET",path:"/api/v3/brokerage/orders/historical/batch"},Un={origin:"RetailBrokerageApi_GetPortfolios",method:"GET",path:"/api/v3/brokerage/portfolios"},qn={origin:"RetailBrokerageApi_GetProduct",method:"GET",path:"/api/v3/brokerage/products/{product_id}"},Bn={origin:"RetailBrokerageApi_GetPublicProductBook",method:"GET",path:"/api/v3/brokerage/market/product_book"},zn={origin:"RetailBrokerageApi_GetTransactionSummary",method:"GET",path:"/api/v3/brokerage/transaction_summary"}});function Lo(t,e){let r={...e},n=t;for(let[i,s]of Object.entries(r)){let o="{"+i+"}";s!=null&&n.includes(o)&&(n=n.replaceAll(o,encodeURIComponent(String(s))),delete r[i])}return{url:n,remaining:r}}async function it(t,e,r,n){let{url:i,remaining:s}=Lo(r,n),o=e==="POST"||e==="PUT"||e==="DELETE"||e==="PATCH",a,c=null;if(o)a=t.baseURL+i,Object.keys(s).length>0&&(c=new TextEncoder().encode(JSON.stringify(s)));else{let u=Object.entries(s).filter(([,f])=>f!=null).flatMap(([f,O])=>(Array.isArray(O)?O:[O]).map(E=>encodeURIComponent(f)+"="+encodeURIComponent(String(E)))).join("&");a=t.baseURL+i+(u?"?"+u:"")}let d=await t.doRequest({method:e,url:a,body:c}),p=new TextDecoder().decode(d.body),_;try{_=JSON.parse(p)}catch{_=p}if(d.status>=400){let u=_,f=u?.error_response?.message??u?.error_response?.error_details??u?.message??u?.error_details??p.slice(0,200);throw new Zt(f,d.status,_)}return{status:d.status,data:_}}function Wn(t,e){return it(t,"POST","/api/v3/brokerage/convert/quote",e)}function $n(t,e){return it(t,"POST","/api/v3/brokerage/orders/edit",e)}function Vn(t,e){return it(t,"GET","/api/v3/brokerage/accounts",e)}function Hn(t,e){return it(t,"GET","/api/v3/brokerage/products/{product_id}/candles",e)}function jn(t,e){return it(t,"GET","/api/v3/brokerage/products/{product_id}/ticker",e)}function Kn(t,e){return it(t,"GET","/api/v3/brokerage/portfolios/{portfolio_uuid}",e)}function lr(t,e){return it(t,"GET","/api/v3/brokerage/products",e)}function Yn(t,e){return it(t,"POST","/api/v3/brokerage/portfolios/move_funds",e)}function Qn(t,e){return it(t,"POST","/api/v3/brokerage/orders",e)}function Jn(t,e){return it(t,"POST","/api/v3/brokerage/orders/preview",e)}var Zt,pt=I(()=>{"use strict";g();l();Zt=class extends Error{status;data;constructor(e,r,n){super(e),this.status=r,this.data=n}}});function Uo(t,e,r){if(!(!t||t===r))return e[t]??t}var Mo,Fo,qo,Xn,Zn=I(()=>{"use strict";g();l();vt();Nt();pt();Mo={FUTURES_POSITION_SIDE_LONG:"LONG",FUTURES_POSITION_SIDE_SHORT:"SHORT"},Fo="FUTURES_POSITION_SIDE_UNSPECIFIED";qo=async(t,e)=>{let n=(await Kn(e,{portfolio_uuid:t.portfolio_id,currency:t.currency})).data.breakdown??{},i=(n.futures_positions??[]).map(s=>({...s,side:Uo(s.side,Mo,Fo)}));return{...n,futures_positions:i}},Xn={portfolios_list:G(Un),portfolios_get:qo,portfolios_create:G(An,{responseUnwrap:"portfolio"}),portfolios_edit:G(Nn,{requestMap:{portfolio_id:"portfolio_uuid"},responseUnwrap:"portfolio"}),portfolios_delete:G(Cn,{requestMap:{portfolio_id:"portfolio_uuid"}})}});var D,mt=I(()=>{"use strict";g();l();D=class t extends Error{status;correlationId;traceId;constructor(e,r,n){super(e),this.status=r,this.correlationId=n?.correlationId,this.traceId=n?.traceId}static stripGrpcPrefix(e){let r=e.match(/^rpc error: code = \w+ desc = (.+)$/s);return r?r[1]:e}static fromResponse(e,r,n){let i=new TextDecoder().decode(e),s,o;try{let c=JSON.parse(i);c.errorType&&c.errorMessage?s=`${c.errorType} \u2014 ${c.errorMessage}`:c.message?s=t.stripGrpcPrefix(c.message):s=i.length>200?i.slice(0,200)+"...":i,o=c.correlationId||c.correlation_id||void 0}catch{s=i.length>200?i.slice(0,200)+"...":i}let a=n?.get("trace-id")??void 0;return new t(s,r,{correlationId:o,traceId:a})}}});function ti(t){return String(t).replace(/^(NEW_ORDER_FAILURE_REASON_|PREVIEW_|EDIT_ORDER_FAILURE_REASON_)/,"").replace(/_/g," ").toLowerCase()}function pr(t){if(t?.success===!1){let e=t.error_response,r=t.errors?.[0]?.edit_failure_reason,n=e?.new_order_failure_reason??e?.preview_failure_reason??e?.error,i=n?ti(n):void 0;throw new D(e?.message||e?.error_details||i||(r?ti(r):void 0)||"Operation failed",400)}}var ei=I(()=>{"use strict";g();l();mt()});var Re,mr,kt,ri=I(()=>{"use strict";g();l();Re={MARKET:"market",LIMIT:"limit",STOP_LIMIT:"stop_limit"},mr={UP:"up",DOWN:"down"},kt={GTC:"GTC",IOC:"IOC",FOK:"FOK",GTD:"GTD"}});import{randomUUID as Bo}from"node:crypto";function ni(t){let e=t.type;if(e===Re.MARKET)return{market_market_ioc:{...t.quote_size&&{quote_size:t.quote_size},...t.base_size&&{base_size:t.base_size}}};if(e===Re.LIMIT){let r=t.time_in_force??kt.GTC,n={base_size:t.base_size,limit_price:t.limit_price,...t.post_only&&{post_only:!0}};return r===kt.IOC?{sor_limit_ioc:n}:r===kt.FOK?{limit_limit_fok:n}:r===kt.GTD?{limit_limit_gtd:{...n,...t.end_time&&{end_time:t.end_time}}}:{limit_limit_gtc:n}}else if(e===Re.STOP_LIMIT){let r=t.stop_direction===mr.UP?"STOP_DIRECTION_STOP_UP":t.stop_direction===mr.DOWN?"STOP_DIRECTION_STOP_DOWN":(()=>{throw new D("stop_direction is required for stop_limit orders (up or down)",400)})(),n=t.time_in_force??kt.GTC,i={base_size:t.base_size,limit_price:t.limit_price,stop_price:t.stop_price,stop_direction:r};return n===kt.GTD?{stop_limit_stop_limit_gtd:{...i,...t.end_time&&{end_time:t.end_time}}}:{stop_limit_stop_limit_gtc:i}}throw new D(`Unknown order type: ${e}. Use market, limit, or stop_limit.`,400)}function zo(t){let e={client_order_id:t.client_order_id??Bo(),product_id:t.product_id,side:t.side,order_configuration:ni(t)};return t.portfolio_id&&(e.retail_portfolio_id=t.portfolio_id),t.reduce_only&&(e.reduce_only=!0),e}var Wo,$o,Vo,Ho,ii,si=I(()=>{"use strict";g();l();vt();mt();ei();ri();Nt();pt();Wo=async(t,e)=>{let r=zo(t),n=await Qn(e,r);return pr(n.data),n.data.success_response??n.data},$o=async(t,e)=>{let r=await Jn(e,{product_id:t.product_id,side:t.side,order_configuration:ni(t)}),n=r.data;if(n.errs?.length>0)throw new D(n.errs[0].replace(/^PREVIEW_/,"").replace(/_/g," ").toLowerCase(),400);return r.data},Vo=async(t,e)=>{if(!t.base_size&&!t.limit_price)throw new D("Provide base_size and/or limit_price to edit",400);let r={order_id:t.order_id,size:t.base_size??"",price:t.limit_price??""},n=await $n(e,r);return pr(n.data),{order_id:t.order_id,status:"EDITED"}},Ho={status:"order_status",side:"order_side",start:"start_date",end:"end_date"},ii={orders_list:G(Fn,{requestMap:Ho}),orders_get:G(Mn,{responseUnwrap:"order"}),orders_create:Wo,orders_preview:$o,orders_edit:Vo,orders_cancel:G(Sn),orders_close_position:G(xn),orders_fills:G(Ln,{requestMap:{side:"order_side",start:"start_sequence_timestamp",end:"end_sequence_timestamp"}})}});function oi(t){return String(Math.floor(new Date(t).getTime()/1e3))}var jo,Ko,Yo,Qo,Jo,Xo,ai,ci=I(()=>{"use strict";g();l();vt();mt();Nt();pt();jo={"1m":"ONE_MINUTE","5m":"FIVE_MINUTE","15m":"FIFTEEN_MINUTE","30m":"THIRTY_MINUTE","1h":"ONE_HOUR","2h":"TWO_HOUR","4h":"FOUR_HOUR","6h":"SIX_HOUR","1d":"ONE_DAY"},Ko={"1m":60,"5m":300,"15m":900,"30m":1800,"1h":3600,"2h":7200,"4h":14400,"6h":21600,"1d":86400},Yo=60,Qo=async(t,e)=>{let{symbol:r,limit:n,cursor:i,...s}=t;if(r){let a=r.toUpperCase(),p=((await lr(e,s)).data.products??[]).filter(u=>u.base_currency_id===a||u.quote_currency_id===a),_=n!==void 0&&n>0?p.slice(0,n):p;return{products:_,num_products:_.length}}return(await lr(e,{...s,limit:n,cursor:i})).data};Jo=async(t,e)=>{if(!t.granularity)throw new D("granularity is required (expected execute() to apply its default)",500);let r=t.granularity,n=jo[r],i=Ko[r],s=Math.floor(Date.now()/1e3),o=t.end?oi(t.end):String(s),a=t.start?oi(t.start):String(Number(o)-Yo*i);return(await Hn(e,{...t,granularity:n,start:a,end:o})).data},Xo=async(t,e)=>{let r=t.limit??100;return(await jn(e,{...t,limit:r})).data},ai={products_list:Qo,products_get:G(qn),products_ticker:Xo,products_book:G(Bn),products_candles:Jo,products_best_bid_ask:G(Gn)}});var Zo,_i,ui=I(()=>{"use strict";g();l();vt();Nt();pt();mt();Zo=async(t,e)=>{let{from:r,to:n,...i}=t,s=await Wn(e,{...i,from_account:r,to_account:n});if(!s.data?.trade?.id)throw new D(`Convert quote returned no trade for ${t.from} \u2192 ${t.to}. Verify balance, supported pair, and account eligibility.`,422);return s.data},_i={convert_quote:Zo,convert_execute:G(wn,{requestMap:{quote_id:"trade_id",from:"from_account",to:"to_account"}}),convert_get:G(Dn,{requestMap:{quote_id:"trade_id",from:"from_account",to:"to_account"},responseUnwrap:"trade"})}});var ta,di,gi=I(()=>{"use strict";g();l();pt();ta=async(t,e)=>{let r={};t.portfolio_id&&(r.retail_portfolio_id=t.portfolio_id),t.limit&&(r.limit=t.limit),t.cursor&&(r.cursor=t.cursor);let i=(await Vn(e,r)).data,s=i.accounts??[],o=t.show_zero?s:s.filter(a=>parseFloat(a.available_balance?.value??"0")!==0||parseFloat(a.hold?.value??"0")!==0);return{accounts:o,has_next:i.has_next,cursor:i.cursor,size:o.length}},di={balance:ta}});var ea,li,pi=I(()=>{"use strict";g();l();mt();pt();ea=async(t,e)=>{let r={funds:{value:t.amount,currency:t.currency},source_portfolio_uuid:t.from,target_portfolio_uuid:t.to},i=(await Yn(e,r)).data;if(!i?.source_portfolio_uuid)throw new D("Transfer failed \u2014 check amount, currency, and portfolio UUIDs",400);return i},li={transfer:ea}});var mi,fi=I(()=>{"use strict";g();l();vt();Nt();mi={fees:G(zn)}});var yi,bi=I(()=>{"use strict";g();l();yi={x402_resources:{endpoint:{origin:"AgentAPI_X402Resources",method:"GET",path:"/x402/resources"}},x402_pay:{endpoint:{origin:"AgentAPI_X402Pay",method:"POST",path:"/x402/pay"}},x402_fetch:{endpoint:{origin:"AgentAPI_X402Fetch",method:"POST",path:"/x402/fetch"}}}});function Pe(t){return ra[t]}var ra,fr=I(()=>{"use strict";g();l();Zn();si();ci();ui();gi();pi();fi();bi();ra={...Xn,...ii,...ai,..._i,...di,...li,...mi,...yi}});function yr(t,e){if(!e)return t;let r={};for(let[n,i]of Object.entries(t)){let s=e[n]??n;r[s]=i}return r}function hi(t,e){if(!e||typeof t!="object"||t===null||Array.isArray(t))return t;let r={};for(let[n,i]of Object.entries(t)){let s=e[n]??n;r[s]=i}return r}var Ei=I(()=>{"use strict";g();l()});function na(t,e){let r={...e},n=t;for(let[i,s]of Object.entries(e)){if(s==null||s==="")continue;let o=`{${i}}`;n.includes(o)&&(n=n.replaceAll(o,encodeURIComponent(String(s))),delete r[i])}return{resolvedPath:n,remainingParams:r}}function ia(t){let e=[];for(let[r,n]of Object.entries(t))if(n!=null)if(Array.isArray(n))for(let i of n)e.push(`${encodeURIComponent(r)}=${encodeURIComponent(String(i))}`);else e.push(`${encodeURIComponent(r)}=${encodeURIComponent(String(n))}`);return e.length>0?"?"+e.join("&"):""}function sa(t,e){if(!e)return t;let r={...t};for(let[n,i]of Object.entries(e)){let s=r[n];if(s!=null){if(i==="join-comma"&&Array.isArray(s))r[n]=s.join(",");else if(i==="split-comma"){let o=Array.isArray(s)?s:[s];r[n]=o.flatMap(a=>String(a).split(",").map(c=>c.trim()).filter(Boolean))}}}return r}function Ii(t,e){return`${t.replace(/\/+$/,"")}${e}`}function oa(t){return t===408||t===429||t>=500}function aa(t){return t instanceof TypeError||t instanceof Error&&(t.name==="AbortError"||t.name==="TimeoutError")}function ca(t,e){if(t&&typeof t=="object"&&!Array.isArray(t)){let r=typeof t.hint=="string"&&t.hint?`${t.hint} `:"";return{...t,hint:`${r}${br}`}}return{error:"AGENT_API_REQUEST_FAILED",code:e,message:typeof t=="string"&&t?t:`Agent API request failed with HTTP ${e}.`,hint:br}}function vi(t,e){return{status:400,data:{error:"REST_ENDPOINT_UNAVAILABLE",code:400,message:`${e} endpoint is not configured for environment "${t.envName}". Configure the endpoint for this environment before retrying.`}}}function _a(t,e){let r=e.split("."),n=t;for(let i of r){if(n==null||typeof n!="object")return t;n=n[i]}return n!==void 0?n:t}function ua(t){return t&&typeof t=="object"&&("body"in t||"query"in t||"path"in t||"rawBody"in t)}function te(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(n=>te(n,e));let r={};for(let n of e.fields){if(!(n in t))continue;let i=e.nested?.[n];i&&Array.isArray(t[n])?r[n]=t[n].map(s=>te(s,i)):i&&typeof t[n]=="object"&&t[n]!==null?r[n]=te(t[n],i):r[n]=t[n]}return r}function da(t,e){let r=hr[t];if(!r)return;if(!e)return r;let n=r;for(let i of e.split(".")){let s=n?.nested?.[i];if(!s)return r;n=s}return n}async function Gt(t,e,r){let n=ua(e),i=n?e.body??{}:{},s=n?e.query??{}:{},o=n?e.path??{}:{},a=n?e.headers??{}:{},c=n?e.rawBody??null:null,d=!1,p=Pe(t);if(!p)return{status:404,data:{error:"UNKNOWN_OPERATION",code:404,message:`No route for ${t}`}};let _=ki.find(m=>m.id===t);if(!n)for(let[m,h]of Object.entries(e)){let A=_?.params.find(ut=>ut.name===m),S=A?.in==="query"?s:A?.in==="path"?o:i;S[m]=h}if(r.transport==="agent"&&!_?.agentApi)return{status:400,data:{error:"AGENT_API_ROUTE_UNAVAILABLE",code:400,message:`${t} is not available through the Agent API. Set COINBASE_TRANSPORT=brokerage to use direct brokerage.`}};let u=_?.agentApi?lt(r.env,r.envName):"",f=_?.agentApi==="only"||r.transport==="agent"||_?.agentApi==="eligible"&&r.transport!=="brokerage"&&!!u;if(_?.params){if(c)try{let m=JSON.parse(new TextDecoder().decode(c));m&&typeof m=="object"&&!Array.isArray(m)&&(d=!0,Object.assign(i,m))}catch{}for(let m of _.params){if(m.default===void 0||m.required||o[m.name]!==void 0||i[m.name]!==void 0||s[m.name]!==void 0)continue;let h=m.in==="query"?s:m.in==="path"?o:i;h[m.name]=m.default}{let m=_.params.filter(S=>(S.in==="body"||!gr(p)&&S.in==="path")&&S.required),h={...o,...i,...s},A=m.filter(S=>h[S.name]===void 0||h[S.name]==="");if(A.length>0)return{status:400,data:{error:"MISSING_FIELDS",code:400,message:`Missing required field(s): ${A.map(ut=>ut.name).join(", ")}`}}}{let m={...o,...i,...s},h={},A={};for(let S of _.params)if(S.oneOf&&(A[S.oneOf]||(A[S.oneOf]=[]),A[S.oneOf].push(S.name),m[S.name]!==void 0&&m[S.name]!=="")){if(h[S.oneOf])return{status:400,data:{error:"CONFLICTING_FIELDS",code:400,message:`${h[S.oneOf]} and ${S.name} are mutually exclusive. Provide one, not both.`}};h[S.oneOf]=S.name}for(let[S,ut]of Object.entries(A))if(!h[S])return{status:400,data:{error:"MISSING_FIELDS",code:400,message:`One of ${ut.join(", ")} is required.`}}}for(let m of _.params)for(let h of[i,s,o]){if(h[m.name]===void 0)continue;if(m.type==="array"&&typeof h[m.name]=="string"&&(h[m.name]=h[m.name].split(",").map(ot=>ot.trim()).filter(Boolean)),m.type==="boolean"){if(typeof h[m.name]!="boolean"&&(typeof h[m.name]!="string"||h[m.name]!=="true"&&h[m.name]!=="false"))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected "true" or "false".`}};typeof h[m.name]=="string"&&(h[m.name]=h[m.name]==="true")}else if((m.type==="integer"||m.type==="number")&&typeof h[m.name]=="string"){let ot=Number(h[m.name]);if(!Number.isFinite(ot))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected a number.`}};h[m.name]=ot}if(m.enum&&!m.enum.includes(String(h[m.name])))return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${h[m.name]}". Expected one of: ${m.enum.join(", ")}`}};let A=m.pattern?Oi.get(m.pattern):void 0,S=m.format?Pn[m.format]:void 0,ut=A??S;if(ut&&typeof h[m.name]=="string"){let ot=h[m.name],Zr=m.format?Tn[m.format]:void 0;if(!(ut.test(ot)&&(!A||!S||S.test(ot))&&(!Zr||Zr(ot)))){let tn=(m.description??"").split(/\.\s/)[0].replace(/\.?\s*$/,""),ao=tn?`. ${tn}.`:".";return{status:400,data:{error:"INVALID_VALUE",code:400,message:`Invalid value for ${m.name}: "${String(ot).slice(0,80)}"${ao}`}}}}}}if(!f&&!r.baseURL)return vi(r,"Brokerage API");if(!f&&!gr(p)){let m={...i,...s,...o};try{let h=await p(m,r),A=hr[t];return A&&(h=te(h,A)),{status:200,data:h}}catch(h){if(h instanceof Zt)return{status:h.status,data:h.data};let A=h instanceof D?h.status:500,S=D.stripGrpcPrefix(h instanceof Error?h.message:String(h));return{status:A,data:{error:"HANDLER_ERROR",code:A,message:S}}}}let O=p,E=f?{origin:"AgentAPI",method:_.method,path:_.agentPath??_.path}:O.endpoint,x=f?void 0:O.requestMap,w=f?void 0:O.responseMap,N=f?void 0:O.responseUnwrap,F={...i,...o},Y=yr(F,x),{resolvedPath:R,remainingParams:P}=na(E.path,Y);if(R.includes("{"))return{status:400,data:{error:"MISSING_PATH_PARAMS",code:400,message:`Missing required param(s): ${(R.match(/\{([^}]+)\}/g)?.map(h=>h.slice(1,-1))??[]).join(", ")}`}};let H=E.method==="POST"||E.method==="PUT"||E.method==="DELETE"||E.method==="PATCH",V,Q=c??null,de={...f?sa(s,_.agentQueryTransforms):yr(s,x)},v=f?u:E.baseURL??r.baseURL;if(!v)return vi(r,f?"Agent API":"Brokerage API");if(H){V=Ii(v,R);let m=f&&Object.keys(o).some(h=>Object.hasOwn(P,h));c&&d&&m?Q=new TextEncoder().encode(JSON.stringify(P)):!Q&&Object.keys(P).length>0&&(Q=new TextEncoder().encode(JSON.stringify(P)))}else Object.assign(de,P),V=Ii(v,R);let T=ia(de);T&&(V+=T);let k;try{k=await r.doRequest({method:E.method,url:V,body:Q,headers:Object.keys(a).length>0?a:void 0})}catch(m){if(!f||_?.agentApi!=="eligible"||!aa(m))throw m;let h=m instanceof Error?m.message:String(m);throw new Error(`${h}
|
|
48
|
+
Hint: ${br}`)}let L=new TextDecoder().decode(k.body),U;try{U=JSON.parse(L)}catch{U=L}if(k.status>=400){let m=f&&_?.agentApi==="eligible"&&oa(k.status)?ca(U,k.status):U;return{status:k.status,data:m,headers:k.headers}}N&&(U=_a(U,N)),w&&(U=hi(U,w));let Et=da(t,N);return Et&&(U=te(U,Et)),{status:k.status,data:U,headers:k.headers}}var ki,hr,Oi,br,Te=I(()=>{"use strict";g();l();vt();fr();Ei();mt();pt();Ct();tt();ki=[...et.flatMap(t=>t.actions),...Object.values(rt)],hr={},Oi=new Map;for(let t of ki){hr[t.id]=t.responseFields;for(let e of t.params)e.pattern&&Oi.set(e.pattern,new RegExp(e.pattern))}br="To bypass the Agent API temporarily, retry with COINBASE_TRANSPORT=brokerage."});import{readFileSync as ga,writeFileSync as la,mkdirSync as pa}from"node:fs";import{join as Pi}from"node:path";function Ri(t){let e=t.replace(/^v/,"").split("-")[0],[r,n,i]=e.split(".").map(Number);return{major:r??0,minor:n??0,patch:i??0}}function fa(t,e){let r=Ri(t),n=Ri(e);return n.major!==r.major?n.major>r.major:n.minor!==r.minor?n.minor>r.minor:n.patch>r.patch}function ba(t,e){let r=ge===ya?"":` --registry ${ge}`;return`
|
|
49
49
|
Update available: ${t} \u2192 ${e}
|
|
50
|
-
Run: npm i -g ${
|
|
51
|
-
`}function
|
|
52
|
-
`)}var Pr,Tr,Xa,xr=I(()=>{"use strict";g();l();Pr={k:1e3,m:1e6,b:1e9};Tr=class{tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.parseOr();if(this.current().type!==11)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().pos}`);return e}parseOr(){let e=this.parseAnd();for(;this.current().type===10;)this.advance(),e={type:"or",left:e,right:this.parseAnd()};return e}parseAnd(){let e=this.parseAtom();for(;this.current().type===9;)this.advance(),e={type:"and",left:e,right:this.parseAtom()};return e}parseAtom(){if(this.current().type===12){this.advance();let e=this.parseOr();if(this.current().type!==13)throw new Error(`Expected ')' at position ${this.current().pos}`);return this.advance(),e}return this.parseComparison()}parseComparison(){let r=this.expect(0,"field name").value,n;this.current().type===0&&this.pos+1<this.tokens.length&&Qa(this.tokens[this.pos+1].type)&&(n=this.advance().value);let i=this.parseOp(),s;if(this.current().type===1)s=this.advance().value;else if(this.current().type===2)s=this.advance().value;else throw new Error(`Expected number or string at position ${this.current().pos}, got '${this.current().value}'`);return{type:"comparison",field:r,product:n,op:i,value:s}}parseOp(){let e=this.current();switch(e.type){case 3:return this.advance(),"==";case 4:return this.advance(),"!=";case 5:return this.advance(),">";case 6:return this.advance(),"<";case 7:return this.advance(),">=";case 8:return this.advance(),"<=";default:throw new Error(`Expected operator at position ${e.pos}, got '${e.value}'`)}}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(e,r){let n=this.current();if(n.type!==e)throw new Error(`Expected ${r} at position ${n.pos}, got '${n.value}'`);return this.advance()}};Xa=/^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/});function it(t){return rc[t]??null}var wr,ec,rc,ie=I(()=>{"use strict";g();l();wr="wss://advanced-trade-ws.coinbase.com",ec="wss://advanced-trade-ws-user.coinbase.com",rc={products_ticker:{name:"ticker",endpoint:wr,requiresAuth:!1,coalesce:!0},products_book:{name:"level2",wireName:"l2_data",endpoint:wr,requiresAuth:!1,coalesce:!0},orders_list:{name:"user",endpoint:ec,requiresAuth:!0,coalesce:!1},products_trades:{name:"market_trades",endpoint:wr,requiresAuth:!1,coalesce:!0}}});var q,nc,ic,De,Le=I(()=>{"use strict";g();l();q={CONNECTING:"CONNECTING",CONNECTED:"CONNECTED",SUBSCRIBED:"SUBSCRIBED",RECONNECTING:"RECONNECTING",FAILED:"FAILED"},nc=3e4,ic=1e3,De=class{url;opts;ws=null;_state=q.CONNECTING;heartbeatTimer=null;reconnectTimer=null;retryCount=0;closed=!1;WSClass;heartbeatTimeoutMs;maxRetries;now;lastActivityTime=0;wasReconnecting=!1;constructor(e,r){this.url=e,this.opts=r,this.WSClass=r.WebSocketClass??globalThis.WebSocket,this.heartbeatTimeoutMs=r.heartbeatTimeoutMs??5e3,this.maxRetries=r.maxRetries??1/0,this.now=r.now??Date.now}get state(){return this._state}connect(){if(!this.closed){this.clearReconnectTimer(),this.teardownSocket(),this.setState(q.CONNECTING);try{this.ws=new this.WSClass(this.url)}catch{this.scheduleReconnect();return}this.resetHeartbeat(),this.ws.onopen=()=>{this.lastActivityTime=this.now(),this.setState(q.CONNECTED),this.resetHeartbeat()},this.ws.onmessage=e=>{let r=this.now();if(this.lastActivityTime>0&&r-this.lastActivityTime>this.heartbeatTimeoutMs*2){this.forceClose();return}this.lastActivityTime=r,this.resetHeartbeat();let n;try{n=typeof e.data=="string"?JSON.parse(e.data):e.data}catch{return}this.opts.onMessage(n)},this.ws.onclose=()=>{this.clearHeartbeat(),this.closed||this.scheduleReconnect()},this.ws.onerror=()=>{}}}send(e){this.ws&&this.ws.readyState===1&&this.ws.send(e)}markSubscribed(){this.setState(q.SUBSCRIBED),this.retryCount=0}close(){this.closed=!0,this.clearHeartbeat(),this.clearReconnectTimer(),this.teardownSocket()}teardownSocket(){this.ws&&(this.ws.onopen=null,this.ws.onclose=null,this.ws.onmessage=null,this.ws.onerror=null,this.ws.readyState<2&&this.ws.close(1e3,"teardown"),this.ws=null)}forceClose(){this.ws&&(this.clearHeartbeat(),this.teardownSocket(),this.scheduleReconnect())}setState(e){this._state=e,e===q.RECONNECTING&&!this.wasReconnecting&&(this.wasReconnecting=!0,this.opts.onDisconnect?.()),e===q.CONNECTED&&this.wasReconnecting&&(this.wasReconnecting=!1,this.opts.onReconnect?.()),this.opts.onStateChange?.(e)}resetHeartbeat(){this.clearHeartbeat(),this.heartbeatTimer=setTimeout(()=>{this.forceClose()},this.heartbeatTimeoutMs)}clearHeartbeat(){this.heartbeatTimer&&(clearTimeout(this.heartbeatTimer),this.heartbeatTimer=null)}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}scheduleReconnect(){if(this.closed)return;if(this.clearReconnectTimer(),this.retryCount>=this.maxRetries){this.setState(q.FAILED);return}this.setState(q.RECONNECTING);let e=Math.min(ic*Math.pow(2,this.retryCount),nc),r=500+Math.random()*(e-500);this.retryCount++,this.reconnectTimer=setTimeout(()=>{this.connect()},r)}}});var Me,ss=I(()=>{"use strict";g();l();Le();Me=class{conn;channel;productIds=[];jwt;lastSeq;hasSubscribed=!1;wasReconnecting=!1;eventHandler;gapHandler;heartbeatHandler;errorHandler;reconnectedHandler;refreshJWTFn;constructor(e){this.channel=e.channel,this.eventHandler=e.onEvent,this.gapHandler=e.onSequenceGap,this.heartbeatHandler=e.onHeartbeat,this.errorHandler=e.onError,this.reconnectedHandler=e.onReconnected,this.refreshJWTFn=e.refreshJWT;let r={onMessage:n=>this.handleMessage(n),onStateChange:n=>{n===q.CONNECTED&&this.hasSubscribed&&(this.refreshJWTFn&&this.wasReconnecting&&(this.jwt=this.refreshJWTFn()),this.lastSeq=void 0,this.sendSubscribe()),e.onStateChange?.(n)},onDisconnect:()=>{this.wasReconnecting=!0,e.onDisconnect?.()},onReconnect:()=>{e.onReconnect?.()},heartbeatTimeoutMs:e.heartbeatTimeoutMs,maxRetries:e.maxRetries,WebSocketClass:e.WebSocketClass,now:e.now};this.conn=new De(e.channel.endpoint,r)}connect(){this.conn.connect()}subscribe(e,r){this.productIds=e,this.jwt=r,this.hasSubscribed=!0,this.lastSeq=void 0,(this.conn.state===q.CONNECTED||this.conn.state===q.SUBSCRIBED)&&this.sendSubscribe()}unsubscribe(e){let r={type:"unsubscribe",channel:this.channel.name};e.length>0&&(r.product_ids=e),this.jwt&&(r.jwt=this.jwt),this.conn.send(JSON.stringify(r));let n={type:"unsubscribe",channel:"heartbeats"};e.length>0&&(n.product_ids=e),this.jwt&&(n.jwt=this.jwt),this.conn.send(JSON.stringify(n)),this.productIds=this.productIds.filter(i=>!e.includes(i))}updateJWT(e){this.jwt=e}close(){this.conn.close()}get state(){return this.conn.state}get subscribedProducts(){return[...this.productIds]}sendSubscribe(){let e={type:"subscribe",channel:this.channel.name};this.productIds.length>0&&(e.product_ids=this.productIds),this.jwt&&(e.jwt=this.jwt),this.conn.send(JSON.stringify(e));let r={type:"subscribe",channel:"heartbeats"};this.productIds.length>0&&(r.product_ids=this.productIds),this.jwt&&(r.jwt=this.jwt),this.conn.send(JSON.stringify(r))}handleMessage(e){if(typeof e!="object"||e===null)return;let r=e;if(r.type==="error"){this.errorHandler?.(String(r.message??r.reason??"unknown error"));return}if(r.type==="subscriptions"||r.channel==="subscriptions"){typeof r.sequence_num=="number"&&(this.lastSeq===void 0||r.sequence_num>this.lastSeq)&&(this.lastSeq=r.sequence_num),this.conn.markSubscribed(),this.wasReconnecting&&(this.wasReconnecting=!1,this.reconnectedHandler?.());return}if(typeof r.sequence_num=="number"){let i=r.sequence_num;if(this.lastSeq!==void 0&&i<=this.lastSeq)return;this.lastSeq!==void 0&&i>this.lastSeq+1&&this.gapHandler?.(this.lastSeq+1,i),(this.lastSeq===void 0||i>this.lastSeq)&&(this.lastSeq=i)}if(r.channel==="heartbeats"){this.heartbeatHandler?.();return}let n=this.channel.wireName??this.channel.name;r.channel===n&&this.eventHandler(e)}}});function Fe(t,e){return Er(t,e,"","","")}var Ar=I(()=>{"use strict";g();l();Ae()});var Ue,os=I(()=>{"use strict";g();l();Ue=class{snapshots=new Map;timestamps=new Map;now;constructor(e){this.now=e??Date.now}update(e,r){this.snapshots.set(e,r),this.timestamps.set(e,this.now())}get(e){return this.snapshots.get(e)}all(){return this.snapshots}isStale(e,r){let n=this.timestamps.get(e);return n===void 0?!1:this.now()-n>r}staleProducts(e,r){let n=new Set;for(let i of e)this.isStale(i,r)&&n.add(i);return n}hasSeen(e){return this.timestamps.has(e)}age(e){let r=this.timestamps.get(e);if(r!==void 0)return this.now()-r}}});function Cr(t,e,r){if(!r||t===0)return"";let n=t>0?Mt:Ft;return e?`${Lt}${n}`:n}function gs(t,e,r){if(!r)return"";let n=t==="bid"||t==="BUY"?Mt:Ft;return e?`${Lt}${n}`:n}var $,Lt,Mt,Ft,as,B,cs,_s,us,ds,Ut=I(()=>{"use strict";g();l();$="\x1B[2m",Lt="\x1B[1m",Mt="\x1B[32m",Ft="\x1B[31m",as="\x1B[33m",B="\x1B[0m",cs="\x1B[?25l",_s="\x1B[?25h",us="\x1B[?1049h",ds="\x1B[?1049l"});var qt,ls=I(()=>{"use strict";g();l();Ut();qt=class{out;inAltScreen=!1;cursorHidden=!1;scrollRegionSet=!1;cleanedUp=!1;resizeHandlers=[];sigwinchHandler=null;sigintHandler=null;sigtermHandler=null;stdinHandler=null;constructor(e){this.out=e??process.stdout}enterAltScreen(){this.out.write(us),this.inAltScreen=!0}exitAltScreen(){this.out.write(ds),this.inAltScreen=!1}hideCursor(){this.out.write(cs),this.cursorHidden=!0}showCursor(){this.out.write(_s),this.cursorHidden=!1}setScrollRegion(e,r){this.out.write(`\x1B[${e};${r}r`),this.scrollRegionSet=!0}resetScrollRegion(){this.out.write("\x1B[r"),this.scrollRegionSet=!1}moveTo(e,r){this.out.write(`\x1B[${e};${r}H`)}clearLine(){this.out.write("\x1B[K")}insertLine(){this.out.write("\x1B[L")}write(e){this.out.write(e)}get cols(){return this.out.columns??80}get rows(){return this.out.rows??24}onResize(e){this.resizeHandlers.push(e),this.sigwinchHandler||(this.sigwinchHandler=()=>{let r=this.cols,n=this.rows;for(let i of this.resizeHandlers)i(r,n)},process.on("SIGWINCH",this.sigwinchHandler))}installSignalHandlers(e){let r=e??(()=>process.exit(0));process.stdin.isTTY&&typeof process.stdin.setRawMode=="function"&&(process.stdin.setRawMode(!0),process.stdin.resume(),this.stdinHandler=n=>{n[0]===3&&(this.cleanup(),r())},process.stdin.on("data",this.stdinHandler)),this.sigintHandler=()=>{this.cleanup(),r()},this.sigtermHandler=()=>{this.cleanup(),r()},process.on("SIGINT",this.sigintHandler),process.on("SIGTERM",this.sigtermHandler)}cleanup(){this.cleanedUp||(this.cleanedUp=!0,process.stdin.isTTY&&typeof process.stdin.setRawMode=="function"&&process.stdin.setRawMode(!1),this.scrollRegionSet&&this.resetScrollRegion(),this.cursorHidden&&this.showCursor(),this.inAltScreen&&this.exitAltScreen(),this.out.write(B),this.removeListeners())}removeListeners(){this.stdinHandler&&(process.stdin.removeListener("data",this.stdinHandler),this.stdinHandler=null,process.stdin.isTTY&&process.stdin.pause()),this.sigwinchHandler&&(process.removeListener("SIGWINCH",this.sigwinchHandler),this.sigwinchHandler=null),this.sigintHandler&&(process.removeListener("SIGINT",this.sigintHandler),this.sigintHandler=null),this.sigtermHandler&&(process.removeListener("SIGTERM",this.sigtermHandler),this.sigtermHandler=null)}}});var se,ps=I(()=>{"use strict";g();l();se=class{flashes=new Map;offsets=new Map;now;constructor(e){this.now=e??Date.now}flash(e,r=600){this.flashes.set(e,this.now()+r)}isFlashing(e){let r=this.flashes.get(e);return r===void 0?!1:this.now()<r}expired(){let e=this.now(),r=[];for(let[n,i]of this.flashes)e>=i&&(r.push(n),this.flashes.delete(n),this.offsets.delete(n));return r}flashWithOffset(e,r,n=1500){let i=this.now()+n;this.flashes.set(e,i),this.offsets.set(e,{indexAtCreation:r,durationMs:n,expiry:i})}getRow(e,r,n){let i=this.offsets.get(e);if(!i)return null;if(this.now()>=i.expiry)return this.offsets.delete(e),null;let s=r-i.indexAtCreation-1;return n+s}clear(){this.flashes.clear(),this.offsets.clear()}}});function W(t,e){let r=mt(t);return r>=e?t.slice(0,t.length-(r-e)):t+" ".repeat(e-r)}function N(t,e){let r=mt(t);return r>=e?t.slice(0,t.length-(r-e)):" ".repeat(e-r)+t}function ft(t,e){let r="\u2500".repeat(t);return e?`${$}${r}${B}`:r}function Bt(t,e,r){let n=mt(t),i=mt(e);if(n+1+i>r){let a=r-i-1;return a>0?`${t.slice(0,a)} ${e}`:e.slice(0,r)}let o=r-n-i;return o<0?W(`${t} ${e}`,r):`${t}${" ".repeat(o)}${e}`}function zt(t,e){return e?t?`${Lt}\xB7${B}`:`${$}\xB7${B}`:""}function K(){let t=new Date,e=String(t.getHours()).padStart(2,"0"),r=String(t.getMinutes()).padStart(2,"0"),n=String(t.getSeconds()).padStart(2,"0");return`${e}:${r}:${n}`}var oe=I(()=>{"use strict";g();l();Ne();Ut()});function j(t){let e=Math.abs(t);return e>=1e3?t.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}):e>=1?t.toFixed(2):t.toFixed(4)}function Wt(t){let e=Math.abs(t);return e>=100?t.toFixed(1):e>=10?t.toFixed(2):e>=1?t.toFixed(3):e>=.01?t.toFixed(4):e>=1e-4?t.toFixed(6):t===0?"0":t.toFixed(8)}function ms(t){return t>=1e9?`${(t/1e9).toFixed(1)}B`:t>=1e6?`${(t/1e6).toFixed(0)}M`:t>=1e3?`${(t/1e3).toFixed(0)}K`:t.toFixed(0)}function fs(t){return`${t>=0?"+":""}${t.toFixed(2)}%`}function ys(t){let e=new Date(t);if(isNaN(e.getTime()))return t;let r=String(e.getHours()).padStart(2,"0"),n=String(e.getMinutes()).padStart(2,"0"),i=String(e.getSeconds()).padStart(2,"0"),s=String(e.getMilliseconds()).padStart(3,"0");return`${r}:${n}:${i}.${s}`}var qe=I(()=>{"use strict";g();l()});function hs(t){let e=[],r=0;for(let n of sc){if(r+n.width+1>t){let i=t-r-1;i>=4&&n.key==="id"&&e.push({...n,width:i});break}e.push(n),r+=n.width+1}return e}function Es(){return{events:[],positions:new Map,openOrders:new Set,totalFees:0,lastClock:K(),netCash:0,fillCount:0,accounted:new Map,prependCount:0,heartbeat:!1,updateCount:0}}function oc(t){let e=t.order_configuration;if(e)for(let r of Object.values(e)){if(r&&typeof r=="object"&&"base_size"in r)return String(r.base_size);if(r&&typeof r=="object"&&"quote_size"in r)return`$${String(r.quote_size)}`}}function ac(t,e){let r=e.creation_time?Date.parse(e.creation_time):NaN;if(Number.isNaN(r))return 0;for(let n=0;n<t.length;n++){let i=t[n].creation_time?Date.parse(t[n].creation_time):NaN;if(!Number.isNaN(i)&&i<r)return n}return t.length}function Nr(t,e,r="live"){let n=t.events;if(!n)return{inserts:[],updates:[]};let i=[],s=[];for(let o of n){let a=o.orders;if(a)for(let c of a){let d={order_id:String(c.order_id??""),status:String(c.status??""),product_id:String(c.product_id??""),order_side:String(c.order_side??c.side??""),order_type:c.order_type?String(c.order_type):void 0,average_filled_price:String(c.average_filled_price??c.avg_price??"0"),total_fees:String(c.total_fees??"0"),filled_size:String(c.filled_size??c.cumulative_quantity??"0"),base_size:oc(c),creation_time:c.creation_time?String(c.creation_time):c.created_time?String(c.created_time):void 0},p=e.events.findIndex(_=>_.order_id===d.order_id);if(p>=0){let _=e.events[p],u=_.status!==d.status||_.filled_size!==d.filled_size||_.total_fees!==d.total_fees||_.average_filled_price!==d.average_filled_price;_.status=d.status,_.average_filled_price=d.average_filled_price,_.filled_size=d.filled_size,_.total_fees=d.total_fees,u&&(bs(e,d),s.push(_));continue}r==="backfill"?e.events.splice(ac(e.events,d),0,d):e.events.unshift(d),e.prependCount++,bs(e,d),i.push(d),e.events.length>1e4&&e.events.pop()}}return{inserts:i,updates:s}}function bs(t,e){t.updateCount++,t.lastClock=K();let r=e.status.toUpperCase();r==="OPEN"||r==="PENDING"?t.openOrders.add(e.order_id):t.openOrders.delete(e.order_id);let n=parseFloat(e.total_fees??"0")||0,i=parseFloat(e.filled_size??"0")||0,s=parseFloat(e.average_filled_price??"0")||0,o=i*s,a=t.accounted.get(e.order_id)??{fees:0,size:0,value:0},c=n-a.fees,d=i-a.size,p=o-a.value;(d!==0||c!==0)&&(a.size===0&&i>0&&t.fillCount++,t.totalFees+=c,e.order_side==="BUY"?(t.netCash-=p,t.positions.set(e.product_id,(t.positions.get(e.product_id)??0)+d)):(t.netCash+=p,t.positions.set(e.product_id,(t.positions.get(e.product_id)??0)-d)),t.accounted.set(e.order_id,{fees:n,size:i,value:o}))}function cc(t,e,r,n,i){let s=e.order_side==="BUY"?"BUY":"SELL",o=gs(s,n,i),a=e.status.toUpperCase(),c=i?B:"",d=parseFloat(e.average_filled_price??"0"),p=parseFloat(e.filled_size??"0");switch(t){case"time":return W(ys(e.creation_time??new Date().toISOString()),r);case"status":return`${(a==="OPEN"||a==="PENDING")&&i?as:""}${W(a,r)}${c}`;case"product":return W(e.product_id,r);case"side":return`${o}${W(s,r)}${c}`;case"size":{let _=p>0?Wt(p):e.base_size??"-";return`${o}${N(_,r)}${c}`}case"price":return`${o}${N(d>0?j(d):"-",r)}${c}`;case"fee":{let _=parseFloat(e.total_fees??"0");return N(_>0?j(_):"-",r)}case"id":return`${i?$:""}${W(e.order_id.slice(0,r),r)}${c}`;default:return W("",r)}}function ae(t,e,r,n=80){return hs(n).map(i=>cc(i.key,t,i.width,e,r)).join(" ")}function _c(t,e=80){let r=new Set(["size","price","fee"]),i=hs(e).map(s=>r.has(s.key)?N(s.header,s.width):W(s.header,s.width)).join(" ");return t?`${$}${i}${B}`:i}function uc(t,e,r){let n=t.netCash>=0?r?Mt:"":r?Ft:"",i=r?B:"",s=`Fills:${t.fillCount}`,o=`Open:${t.openOrders.size}`,a=`Fees:${j(t.totalFees)}`,c=`Net:${t.netCash>=0?"+":""}${j(t.netCash)}`,d=`${n}${c}${i}`,_=`${zt(t.heartbeat,r)} ${t.lastClock}`,u=`\xB7 ${t.lastClock}`,f=`${s} ${o} ${a} ${c}`,O=`${s} ${o} ${a} ${d}`,E=new Map;for(let[R,P]of t.positions){if(Math.abs(P)<1e-9)continue;let V=(R.match(/-/g)??[]).length===1?R.slice(0,R.indexOf("-")):R;E.set(V,(E.get(V)??0)+P)}let x=[],w=[];for(let[R,P]of E){if(Math.abs(P)<1e-9)continue;let H=`${R}:${Wt(P)}`;x.push(H),w.push(H)}let G=e-f.length-u.length-6,F="";if(x.length>0&&G>8){let R="",P=0,H=0;for(let V=0;V<x.length;V++){let Q=H>0?" ":"";if(P+Q.length+w[V].length>G){let Ht=x.length-H;Ht>0&&(R+=` +${Ht}`);break}R+=Q+x[V],P+=Q.length+w[V].length,H++}F=R}let Y=F?`${O} ${F}`:O;return Bt(Y,_,e)}function Is(t,e,r,n,i){let s=i??e.events,o=t.cols,a=t.rows,c=a,d=a-1,p=a-2;n.inserts.forEach((_,u)=>{r.flashWithOffset(_.order_id,e.prependCount-1-u,1500),t.moveTo(Be,1),t.insertLine(),t.write(ae(_,!0,!0,t.cols)+"\x1B[K")});for(let _ of n.updates){let u=s.indexOf(_);if(u>=0){let f=Be+u;f<=p&&(r.flash(_.order_id,1500),t.moveTo(f,1),t.write(ae(_,!0,!0,t.cols)+"\x1B[K"))}}for(let _ of r.expired()){let u=s.findIndex(f=>f.order_id===_);if(u>=0){let f=Be+u;f<=p&&(t.moveTo(f,1),t.write(ae(s[u],!1,!0,t.cols)+"\x1B[K"))}}t.moveTo(d,1),t.write(ft(o,!0)),t.moveTo(c,1),t.write(uc(e,o-1,!0)+"\x1B[K")}function Gr(t){t.enterAltScreen(),t.hideCursor();let e=t.rows;t.setScrollRegion(Be,e-2),t.moveTo(1,1),t.write(_c(!0,t.cols)+"\x1B[K"),t.moveTo(2,1),t.write(ft(t.cols,!0))}function ze(t,e,r){return{_ch:"user",_seq:e,_ts:r,order_id:t.order_id,status:t.status,product_id:t.product_id,side:t.order_side,filled_size:t.filled_size??null,price:t.average_filled_price??null,fees:t.total_fees??null}}function ks(t,e,r){return JSON.stringify(ze(t,e,r))}var Be,sc,vs=I(()=>{"use strict";g();l();oe();Ut();qe();Be=3,sc=[{header:"TIME",width:13,key:"time"},{header:"STATUS",width:10,key:"status"},{header:"PRODUCT",width:10,key:"product"},{header:"SIDE",width:5,key:"side"},{header:"SIZE",width:12,key:"size"},{header:"PRICE",width:12,key:"price"},{header:"FEE",width:8,key:"fee"},{header:"ORDER ID",width:12,key:"id"}]});function Os(t,e,r,n=8){let i=r-e;if(i<=0)return"\u2500".repeat(n);let s=Math.max(0,Math.min(1,(t-e)/i)),o=Math.round(s*(n-1)),a="";for(let c=0;c<n;c++)a+=c===o?"\u25CF":"\u2500";return a}function Rs(t,e,r){if(e<=0||t<=0)return"";let n=Math.max(0,Math.round(t/e*r));return"\u2588".repeat(n)}var Dr=I(()=>{"use strict";g();l()});function Ss(t){let e=[],r=0;for(let n of lc){if(r+n.width+1>t)break;e.push(n),r+=n.width+1}return e}function xs(){return{products:new Map,prevPrices:new Map,productOrder:[],heartbeat:!1,updateCount:0,lastClock:K()}}function ws(t,e){let r=t.events;if(!r)return[];let n=[];for(let i of r){let s=i.tickers;if(s)for(let o of s){let a={product_id:String(o.product_id??""),price:String(o.price??"0"),volume_24_h:String(o.volume_24_h??"0"),price_percent_chg_24_h:String(o.price_percent_chg_24_h??"0"),best_bid:String(o.best_bid??"0"),best_bid_quantity:String(o.best_bid_quantity??"0"),best_ask:String(o.best_ask??"0"),best_ask_quantity:String(o.best_ask_quantity??"0"),high_24_h:String(o.high_24_h??"0"),low_24_h:String(o.low_24_h??"0")},c=e.prevPrices.get(a.product_id),d=parseFloat(a.price),p=0;c!==void 0&&(d>c?p=1:d<c&&(p=-1)),e.prevPrices.set(a.product_id,d),e.products.set(a.product_id,a),e.productOrder.includes(a.product_id)||e.productOrder.push(a.product_id),e.updateCount++,e.lastClock=K(),n.push({ticker:a,direction:p})}}return n}function pc(t,e,r,n,i,s){let o=parseFloat(e.price),a=s?B:"";switch(t){case"symbol":return W(e.product_id,r);case"price":return`${Cr(n,i,s)}${N(j(o),r)}${a}`;case"pct":{let c=parseFloat(e.price_percent_chg_24_h),d=c>0?1:c<0?-1:0;return`${Cr(d,!1,s)}${N(fs(c),r)}${a}`}case"bid":return N(j(parseFloat(e.best_bid)),r);case"ask":return N(j(parseFloat(e.best_ask)),r);case"bidSz":return`${s?$:""}${N(Wt(parseFloat(e.best_bid_quantity)),r)}${a}`;case"askSz":return`${s?$:""}${N(Wt(parseFloat(e.best_ask_quantity)),r)}${a}`;case"low":return`${s?$:""}${N(j(parseFloat(e.low_24_h)),r)}${a}`;case"high":return`${s?$:""}${N(j(parseFloat(e.high_24_h)),r)}${a}`;case"range":return W(Os(o,parseFloat(e.low_24_h),parseFloat(e.high_24_h),r),r);case"vol":return`${s?$:""}${N(ms(parseFloat(e.volume_24_h)),r)}${a}`;default:return W("",r)}}function Ts(t,e,r,n,i=80){return Ss(i).map(o=>pc(o.key,t,o.width,e,r,n)).join(" ")}function mc(t,e=80){let n=Ss(e).map(i=>i.key==="symbol"||i.key==="range"?W(i.header,i.width):N(i.header,i.width)).join(" ");return t?`${$}${n}${B}`:n}function fc(t,e,r){let n=`${t.products.size} product${t.products.size!==1?"s":""}`,s=`${zt(t.heartbeat,r)} ${t.lastClock}`;return Bt(n,s,e)}function Lr(t){t.enterAltScreen(),t.hideCursor(),t.moveTo(dc,1),t.write(mc(!0,t.cols)+"\x1B[K"),t.moveTo(gc,1),t.write(ft(t.cols,!0))}function As(t,e,r,n,i){let s=t.cols,o=t.rows,a=o,c=o-1;for(let{ticker:d,direction:p}of n){let _=e.productOrder.indexOf(d.product_id);if(_<0)continue;let u=Ps+_;if(u>=c)continue;let f=i?.has(d.product_id)??!1,O=!f&&r.isFlashing(d.product_id);t.moveTo(u,1);let E=Ts(d,f?0:p,O,!0,s);t.write((f?$+E+B:E)+"\x1B[K")}for(let d of r.expired()){let p=e.productOrder.indexOf(d);if(p<0)continue;let _=Ps+p;if(_>=c)continue;let u=e.products.get(d);u&&(t.moveTo(_,1),t.write(Ts(u,0,!1,!0,s)+"\x1B[K"))}t.moveTo(c,1),t.write(ft(s,!0)),t.moveTo(a,1),t.write(fc(e,s-1,!0)+"\x1B[K")}function Mr(t,e,r){return{_ch:"ticker",_seq:e,_ts:r,product_id:t.product_id,price:t.price,pct_24h:t.price_percent_chg_24_h,bid:t.best_bid,bid_size:t.best_bid_quantity,ask:t.best_ask,ask_size:t.best_ask_quantity,volume:t.volume_24_h,high:t.high_24_h,low:t.low_24_h}}function Cs(t,e,r){return JSON.stringify(Mr(t,e,r))}var dc,gc,Ps,lc,Ns=I(()=>{"use strict";g();l();oe();Ut();qe();Dr();dc=1,gc=2,Ps=3,lc=[{header:"SYMBOL",width:10,key:"symbol"},{header:"PRICE",width:12,key:"price"},{header:"%24h",width:8,key:"pct"},{header:"BID",width:11,key:"bid"},{header:"ASK",width:11,key:"ask"},{header:"LOW",width:11,key:"low"},{header:"RANGE",width:10,key:"range"},{header:"HIGH",width:11,key:"high"},{header:"BIDSZ",width:7,key:"bidSz"},{header:"ASKSZ",width:7,key:"askSz"},{header:"VOL",width:6,key:"vol"}]});function Ds(t,e=0){return{productId:t,bids:new Map,asks:new Map,heartbeat:!1,updateCount:0,msgCount:0,lastMsgTime:Date.now(),msgRate:0,depth:e,lastClock:K()}}function Ls(t,e){let r=t.events;if(!r)return;e.msgCount++;let n=Date.now(),i=(n-e.lastMsgTime)/1e3;i>=1&&(e.msgRate=Math.round(e.msgCount/i),e.msgCount=0,e.lastMsgTime=n);for(let s of r){let o=s.type,a=s.updates;if(o==="snapshot"&&(e.bids.clear(),e.asks.clear()),!!a){for(let c of a){let d=String(c.side??"").toLowerCase(),p=parseFloat(String(c.price_level??"0")),_=parseFloat(String(c.new_quantity??"0"));if(p<=0)continue;let u=d==="bid"?e.bids:e.asks;_<=0?u.delete(p):u.set(p,_)}e.updateCount++,e.lastClock=K()}}}function We(t){let e=[];for(let[r,n]of t.bids)e.push({price:r,size:n});return e.sort((r,n)=>n.price-r.price),e}function $e(t){let e=[];for(let[r,n]of t.asks)e.push({price:r,size:n});return e.sort((r,n)=>r.price-n.price),e}function Gs(t,e,r,n,i,s,o){let a=o?i==="bid"?Mt:Ft:"",c=o?B:"",d=Rs(r,n,s),p=`${a}${d}${c}`;return[`${a}${N(j(t),yt[0])}${c}`,N(e.toFixed(4),yt[1]),N(r.toFixed(4),yt[2]),p].join(" ")}function hc(t,e,r){let n=$e(t),i=We(t),s=n.length>0?n[0].price:0,o=i.length>0?i[0].price:0,a=s-o,c=(s+o)/2,d=c>0?a/c*100:0,p=c>0?` Spread: ${j(a).padStart(10)} (${d.toFixed(3).padStart(6)}%) Mid: ${j(c).padStart(12)}`:" Waiting for data...",_=r?$:"",u=r?B:"";return`${_}${W(p,e)}${u}`}function Ec(t,e,r){let n=bc.map((c,d)=>d===3?W(c,yt[d]):N(c,yt[d])).join(" "),i=r?$:"",s=r?Lt:"",o=r?B:"",a=`${s}${t.productId}${o}`;return`${W(a,e)}
|
|
53
|
-
${i}${n}${o}`}function
|
|
54
|
-
Set up a CDP key: coinbase env <name> --key-file key.json`);if(n.type==="cdp_key"&&n.key_id&&n.key_secret)return
|
|
50
|
+
Run: npm i -g ${Se}${r}
|
|
51
|
+
`}function xi(){return gt()}function Ea(){try{return JSON.parse(ga(Pi(xi(),Si),"utf8"))}catch{return null}}function Ia(t){try{let e=xi();pa(e,{recursive:!0}),la(Pi(e,Si),JSON.stringify(t))}catch{}}async function va(){try{let t=new AbortController,e=setTimeout(()=>t.abort(),3e3),r=await fetch(ma,{signal:t.signal,headers:{Accept:"application/json"}});return clearTimeout(e),r.ok?(await r.json())?.["dist-tags"]?.latest??null:null}catch{return null}}async function wi(){if(process.env.CI||process.env.COINBASE_NO_UPDATE_CHECK)return"";let t=Ea();if(t&&Date.now()-t.checkedAt<ha)return"";let e=await va();return e?(Ia({checkedAt:Date.now(),latestVersion:e}),fa(ct,e)?ba(ct,e):""):""}var Ti,ct,Se,ma,Si,ya,ha,xe=I(()=>{"use strict";g();l();le();tt();Ti="0.0.6";ct=Ti,Se=en,ma=`${ge}/${encodeURIComponent(Se)}`,Si="version-check.json";ya="https://registry.npmjs.org";ha=1440*60*1e3});import{createSign as ka,createPrivateKey as Oa,sign as Ra,randomBytes as Pa}from"node:crypto";function Er(t){return Buffer.from(t).toString("base64url")}function we(t){return Er(Buffer.from(JSON.stringify(t)))}function Ta(){return Pa(16).toString("hex")}function Ci(t){return t.includes("-----BEGIN EC PRIVATE KEY-----")}function Ni(t){let e=Buffer.from(t,"base64");return e.length===32||e.length===64}function Ir(t,e,r,n,i){let s=Math.floor(Date.now()/1e3),o=Ta(),a={sub:t,iss:"cdp",nbf:s,iat:s,exp:s+120},c=`${r} ${n}${i}`;if(r&&n&&i&&(a.uris=[c]),Ci(e))return xa(t,e,a,o);if(Ni(e))return wa(t,e,a,o);throw new Error("invalid key format - must be either PEM EC key or base64 Ed25519 key")}function Sa(t,e,r){let n=`${we(t)}.${we(e)}`,i=ka("SHA256");i.update(n);let s=i.sign(r);return`${n}.${Er(Aa(s))}`}function xa(t,e,r,n){return Sa({alg:"ES256",typ:"JWT",kid:t,nonce:n},r,e)}function wa(t,e,r,n){let s=`${we({alg:"EdDSA",typ:"JWT",kid:t,nonce:n})}.${we(r)}`,o=Buffer.from(e,"base64"),a=Oa({key:Buffer.concat([Buffer.from("302e020100300506032b657004220420","hex"),o.subarray(0,32)]),format:"der",type:"pkcs8"}),c=Ra(null,Buffer.from(s),a);return`${s}.${Er(c)}`}function Aa(t){let e=2;if(t[e]!==2)throw new Error("invalid DER signature");e++;let r=t[e];e++;let n=t.subarray(e,e+r);if(e+=r,t[e]!==2)throw new Error("invalid DER signature");e++;let i=t[e];e++;let s=t.subarray(e,e+i);return n=Ai(n,32),s=Ai(s,32),Buffer.concat([n,s])}function Ai(t,e){if(t.length===e)return Buffer.from(t);if(t.length>e)return Buffer.from(t.subarray(t.length-e));let r=Buffer.alloc(e);return r.set(t,e-t.length),r}function Ca(t){return Ci(t)?"ecdsa":Ni(t)?"ed25519":"unknown"}async function Ae(t){let e;if(t.keyId&&t.keySecret){let o=new URL(t.url);e=`Bearer ${Ir(t.keyId,t.keySecret,t.method,o.host,o.pathname)}`}else throw new Error("doAuthenticatedRequest: must supply keyId+keySecret");let r={Authorization:e,"Content-Type":"application/json","Correlation-Context":`sdk_version=${encodeURIComponent(ct)},sdk_language=typescript,source=${encodeURIComponent(Se)}`,...t.headers},n=await fetch(t.url,{method:t.method,headers:r,body:t.body?Buffer.from(t.body):void 0}),s={body:new Uint8Array(await n.arrayBuffer()),status:n.status,headers:n.headers};return n.status===401&&t.keySecret&&Ca(t.keySecret)==="ed25519"&&(s.hint="CDP key is Ed25519 but Coinbase Advanced Trade requires ECDSA. Create an ECDSA key at https://portal.cdp.coinbase.com/projects/api-keys (set Signature algorithm to ECDSA at key creation), then `coinbase env <name> --key-file ...`."),s}var Ce=I(()=>{"use strict";g();l();xe()});function tc(t,e){return t.FORCE_HYPERLINK==="0"?!1:t.FORCE_HYPERLINK?!0:!e||t.CI?!1:!!(/ghostty|iterm|wezterm|hyper/i.test(t.TERM_PROGRAM||"")||t.WT_SESSION||parseInt(t.VTE_VERSION||"",10)>=5e3)}function ft(t){return t.replace(/\x1b\]8;;[^\x07]*\x07/g,"").replace(/\x1b\[[0-9;]*m/g,"").length}var es,Ge=I(()=>{"use strict";g();l();es=tc(process.env,!!process.stdout.isTTY)});function rc(t){let e=[],r=0;for(;r<t.length;){if(t[r]===" "||t[r]===" "){r++;continue}let n=r;if(t[r]==="("){e.push({type:12,value:"(",pos:n}),r++;continue}if(t[r]===")"){e.push({type:13,value:")",pos:n}),r++;continue}if(r+1<t.length){let i=t[r]+t[r+1];if(i==="=="){e.push({type:3,value:"==",pos:n}),r+=2;continue}if(i==="!="){e.push({type:4,value:"!=",pos:n}),r+=2;continue}if(i===">="){e.push({type:7,value:">=",pos:n}),r+=2;continue}if(i==="<="){e.push({type:8,value:"<=",pos:n}),r+=2;continue}if(i==="&&"){e.push({type:9,value:"&&",pos:n}),r+=2;continue}if(i==="||"){e.push({type:10,value:"||",pos:n}),r+=2;continue}}if(t[r]===">"){e.push({type:5,value:">",pos:n}),r++;continue}if(t[r]==="<"){e.push({type:6,value:"<",pos:n}),r++;continue}if(t[r]==='"'){r++;let i="";for(;r<t.length&&t[r]!=='"';)t[r]==="\\"&&r+1<t.length&&r++,i+=t[r],r++;if(r>=t.length)throw new Error(`Unterminated string at position ${n}`);r++,e.push({type:2,value:i,pos:n});continue}if(t[r]==="-"||t[r]>="0"&&t[r]<="9"){let i="";if(t[r]==="-")if(r+1<t.length&&t[r+1]>="0"&&t[r+1]<="9")i+=t[r],r++;else throw new Error(`Unexpected character '-' at position ${n}`);for(;r<t.length&&t[r]>="0"&&t[r]<="9";)i+=t[r],r++;if(r<t.length&&t[r]===".")for(i+=".",r++;r<t.length&&t[r]>="0"&&t[r]<="9";)i+=t[r],r++;let s=r<t.length?t[r]:"",o=s.toLowerCase()in Tr&&(r+1>=t.length||t[r+1]===" "||t[r+1]===" "||t[r+1]===")"||t[r+1]==="&"||t[r+1]==="|");if(s&&!o&&(s>="a"&&s<="z"||s>="A"&&s<="Z"||s==="-"))r=n;else{let a=parseFloat(i);r<t.length&&t[r].toLowerCase()in Tr&&(a*=Tr[t[r].toLowerCase()],r++),e.push({type:1,value:a,pos:n});continue}}if(t[r]>="a"&&t[r]<="z"||t[r]>="A"&&t[r]<="Z"||t[r]==="_"||t[r]>="0"&&t[r]<="9"){let i="";for(;r<t.length&&(t[r]>="a"&&t[r]<="z"||t[r]>="A"&&t[r]<="Z"||t[r]>="0"&&t[r]<="9"||t[r]==="_"||t[r]==="-");)i+=t[r],r++;e.push({type:0,value:i,pos:n});continue}throw new Error(`Unexpected character '${t[r]}' at position ${n}`)}return e.push({type:11,value:"",pos:r}),e}function nc(t){return t>=3&&t<=8}function xr(t){let e=t.trim();if(e.length===0)throw new Error("Empty predicate");return new Sr(rc(e)).parse()}function ie(t){switch(t.type){case"comparison":return t.product?[t.product]:[];case"and":case"or":return[...ie(t.left),...ie(t.right)]}}function is(t,e){let r=[];function n(i){switch(i.type){case"comparison":{let s=e[i.field];if(!s){r.push({field:i.field,message:`Unknown field '${i.field}'`});return}s.type==="string"&&typeof i.value=="number"&&r.push({field:i.field,message:`'${i.field}' is a string field \u2014 use "${i.value}" not ${i.value}`}),s.type==="number"&&typeof i.value=="string"&&r.push({field:i.field,message:`'${i.field}' is a numeric field \u2014 use ${i.value} not "${i.value}"`}),s.type==="string"&&(i.op===">"||i.op==="<"||i.op===">="||i.op==="<=")&&r.push({field:i.field,message:`'${i.field}' is a string field \u2014 only == and != are supported`}),s.enum&&typeof i.value=="string"&&!s.enum.includes(i.value)&&r.push({field:i.field,message:`'${i.value}' is not valid for '${i.field}' \u2014 expected: ${s.enum.join(", ")}`});break}case"and":case"or":n(i.left),n(i.right);break}}return n(t),r}function ic(t,e){let r=e.split("."),n=t;for(let i of r){if(n==null||typeof n!="object")return;n=n[i]}return n}function oc(t,e){if(typeof e=="number"){if(typeof t=="number")return[t,e];if(typeof t=="string"&&sc.test(t))return[parseFloat(t),e]}return null}function ac(t,e,r){let n=t.product&&r?r.get(t.product)??e:e;if(t.product&&n.product_id!==t.product)return!1;let i=ic(n,t.field);if(i==null)return!1;let s=oc(i,t.value);switch(t.op){case"==":return s?s[0]===s[1]:i===t.value;case"!=":return s?s[0]!==s[1]:i!==t.value;case">":return s?s[0]>s[1]:!1;case"<":return s?s[0]<s[1]:!1;case">=":return s?s[0]>=s[1]:!1;case"<=":return s?s[0]<=s[1]:!1}}function Dt(t,e,r){switch(t.type){case"comparison":return ac(t,e,r);case"and":return Dt(t.left,e,r)&&Dt(t.right,e,r);case"or":return Dt(t.left,e,r)||Dt(t.right,e,r)}}function ss(t){let e=[];e.push(" --until <predicate> Exit when predicate matches"),e.push(""),e.push(" Predicate: field [product] op value [&& | || ...]"),e.push(" Operators: == != > < >= <="),e.push(" Grouping: ( )"),e.push(" Suffixes: k (1,000) m (1,000,000) b (1,000,000,000)"),e.push(""),e.push(" Fields:");let r=Math.max(...Object.keys(t).map(s=>s.length));for(let[s,o]of Object.entries(t)){let a=o.enum?o.enum.join("|"):o.type;e.push(` ${s.padEnd(r)} ${a.padEnd(12)} ${o.description}`)}let n=Object.entries(t).filter(([,s])=>s.type==="number").map(([s])=>s),i=Object.entries(t).filter(([,s])=>s.enum).map(([s,o])=>({k:s,vals:o.enum}));if(e.push(""),e.push(" Examples:"),n.length>0&&e.push(` --until "${n[0]} > 70k"`),n.length>1&&e.push(` --until "${n[0]} >= 70k && ${n[0]} <= 75k"`),i.length>0){let s=i[0];e.push(` --until "${s.k} == \\"${s.vals[0]}\\""`)}return n.length>0&&e.push(` --until "(${n[0]} > 72k || ${n[0]} < 68k)"`),e.join(`
|
|
52
|
+
`)}var Tr,Sr,sc,wr=I(()=>{"use strict";g();l();Tr={k:1e3,m:1e6,b:1e9};Sr=class{tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.parseOr();if(this.current().type!==11)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().pos}`);return e}parseOr(){let e=this.parseAnd();for(;this.current().type===10;)this.advance(),e={type:"or",left:e,right:this.parseAnd()};return e}parseAnd(){let e=this.parseAtom();for(;this.current().type===9;)this.advance(),e={type:"and",left:e,right:this.parseAtom()};return e}parseAtom(){if(this.current().type===12){this.advance();let e=this.parseOr();if(this.current().type!==13)throw new Error(`Expected ')' at position ${this.current().pos}`);return this.advance(),e}return this.parseComparison()}parseComparison(){let r=this.expect(0,"field name").value,n;this.current().type===0&&this.pos+1<this.tokens.length&&nc(this.tokens[this.pos+1].type)&&(n=this.advance().value);let i=this.parseOp(),s;if(this.current().type===1)s=this.advance().value;else if(this.current().type===2)s=this.advance().value;else throw new Error(`Expected number or string at position ${this.current().pos}, got '${this.current().value}'`);return{type:"comparison",field:r,product:n,op:i,value:s}}parseOp(){let e=this.current();switch(e.type){case 3:return this.advance(),"==";case 4:return this.advance(),"!=";case 5:return this.advance(),">";case 6:return this.advance(),"<";case 7:return this.advance(),">=";case 8:return this.advance(),"<=";default:throw new Error(`Expected operator at position ${e.pos}, got '${e.value}'`)}}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(e,r){let n=this.current();if(n.type!==e)throw new Error(`Expected ${r} at position ${n.pos}, got '${n.value}'`);return this.advance()}};sc=/^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/});function st(t){return _c[t]??null}var Ar,cc,_c,se=I(()=>{"use strict";g();l();Ar="wss://advanced-trade-ws.coinbase.com",cc="wss://advanced-trade-ws-user.coinbase.com",_c={products_ticker:{name:"ticker",endpoint:Ar,requiresAuth:!1,coalesce:!0},products_book:{name:"level2",wireName:"l2_data",endpoint:Ar,requiresAuth:!1,coalesce:!0},orders_list:{name:"user",endpoint:cc,requiresAuth:!0,coalesce:!1},products_trades:{name:"market_trades",endpoint:Ar,requiresAuth:!1,coalesce:!0}}});var q,uc,dc,Le,Me=I(()=>{"use strict";g();l();q={CONNECTING:"CONNECTING",CONNECTED:"CONNECTED",SUBSCRIBED:"SUBSCRIBED",RECONNECTING:"RECONNECTING",FAILED:"FAILED"},uc=3e4,dc=1e3,Le=class{url;opts;ws=null;_state=q.CONNECTING;heartbeatTimer=null;reconnectTimer=null;retryCount=0;closed=!1;WSClass;heartbeatTimeoutMs;maxRetries;now;lastActivityTime=0;wasReconnecting=!1;constructor(e,r){this.url=e,this.opts=r,this.WSClass=r.WebSocketClass??globalThis.WebSocket,this.heartbeatTimeoutMs=r.heartbeatTimeoutMs??5e3,this.maxRetries=r.maxRetries??1/0,this.now=r.now??Date.now}get state(){return this._state}connect(){if(!this.closed){this.clearReconnectTimer(),this.teardownSocket(),this.setState(q.CONNECTING);try{this.ws=new this.WSClass(this.url)}catch{this.scheduleReconnect();return}this.resetHeartbeat(),this.ws.onopen=()=>{this.lastActivityTime=this.now(),this.setState(q.CONNECTED),this.resetHeartbeat()},this.ws.onmessage=e=>{let r=this.now();if(this.lastActivityTime>0&&r-this.lastActivityTime>this.heartbeatTimeoutMs*2){this.forceClose();return}this.lastActivityTime=r,this.resetHeartbeat();let n;try{n=typeof e.data=="string"?JSON.parse(e.data):e.data}catch{return}this.opts.onMessage(n)},this.ws.onclose=()=>{this.clearHeartbeat(),this.closed||this.scheduleReconnect()},this.ws.onerror=()=>{}}}send(e){this.ws&&this.ws.readyState===1&&this.ws.send(e)}markSubscribed(){this.setState(q.SUBSCRIBED),this.retryCount=0}close(){this.closed=!0,this.clearHeartbeat(),this.clearReconnectTimer(),this.teardownSocket()}teardownSocket(){this.ws&&(this.ws.onopen=null,this.ws.onclose=null,this.ws.onmessage=null,this.ws.onerror=null,this.ws.readyState<2&&this.ws.close(1e3,"teardown"),this.ws=null)}forceClose(){this.ws&&(this.clearHeartbeat(),this.teardownSocket(),this.scheduleReconnect())}setState(e){this._state=e,e===q.RECONNECTING&&!this.wasReconnecting&&(this.wasReconnecting=!0,this.opts.onDisconnect?.()),e===q.CONNECTED&&this.wasReconnecting&&(this.wasReconnecting=!1,this.opts.onReconnect?.()),this.opts.onStateChange?.(e)}resetHeartbeat(){this.clearHeartbeat(),this.heartbeatTimer=setTimeout(()=>{this.forceClose()},this.heartbeatTimeoutMs)}clearHeartbeat(){this.heartbeatTimer&&(clearTimeout(this.heartbeatTimer),this.heartbeatTimer=null)}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}scheduleReconnect(){if(this.closed)return;if(this.clearReconnectTimer(),this.retryCount>=this.maxRetries){this.setState(q.FAILED);return}this.setState(q.RECONNECTING);let e=Math.min(dc*Math.pow(2,this.retryCount),uc),r=500+Math.random()*(e-500);this.retryCount++,this.reconnectTimer=setTimeout(()=>{this.connect()},r)}}});var Fe,os=I(()=>{"use strict";g();l();Me();Fe=class{conn;channel;productIds=[];jwt;lastSeq;hasSubscribed=!1;wasReconnecting=!1;eventHandler;gapHandler;heartbeatHandler;errorHandler;reconnectedHandler;refreshJWTFn;constructor(e){this.channel=e.channel,this.eventHandler=e.onEvent,this.gapHandler=e.onSequenceGap,this.heartbeatHandler=e.onHeartbeat,this.errorHandler=e.onError,this.reconnectedHandler=e.onReconnected,this.refreshJWTFn=e.refreshJWT;let r={onMessage:n=>this.handleMessage(n),onStateChange:n=>{n===q.CONNECTED&&this.hasSubscribed&&(this.refreshJWTFn&&this.wasReconnecting&&(this.jwt=this.refreshJWTFn()),this.lastSeq=void 0,this.sendSubscribe()),e.onStateChange?.(n)},onDisconnect:()=>{this.wasReconnecting=!0,e.onDisconnect?.()},onReconnect:()=>{e.onReconnect?.()},heartbeatTimeoutMs:e.heartbeatTimeoutMs,maxRetries:e.maxRetries,WebSocketClass:e.WebSocketClass,now:e.now};this.conn=new Le(e.channel.endpoint,r)}connect(){this.conn.connect()}subscribe(e,r){this.productIds=e,this.jwt=r,this.hasSubscribed=!0,this.lastSeq=void 0,(this.conn.state===q.CONNECTED||this.conn.state===q.SUBSCRIBED)&&this.sendSubscribe()}unsubscribe(e){let r={type:"unsubscribe",channel:this.channel.name};e.length>0&&(r.product_ids=e),this.jwt&&(r.jwt=this.jwt),this.conn.send(JSON.stringify(r));let n={type:"unsubscribe",channel:"heartbeats"};e.length>0&&(n.product_ids=e),this.jwt&&(n.jwt=this.jwt),this.conn.send(JSON.stringify(n)),this.productIds=this.productIds.filter(i=>!e.includes(i))}updateJWT(e){this.jwt=e}close(){this.conn.close()}get state(){return this.conn.state}get subscribedProducts(){return[...this.productIds]}sendSubscribe(){let e={type:"subscribe",channel:this.channel.name};this.productIds.length>0&&(e.product_ids=this.productIds),this.jwt&&(e.jwt=this.jwt),this.conn.send(JSON.stringify(e));let r={type:"subscribe",channel:"heartbeats"};this.productIds.length>0&&(r.product_ids=this.productIds),this.jwt&&(r.jwt=this.jwt),this.conn.send(JSON.stringify(r))}handleMessage(e){if(typeof e!="object"||e===null)return;let r=e;if(r.type==="error"){this.errorHandler?.(String(r.message??r.reason??"unknown error"));return}if(r.type==="subscriptions"||r.channel==="subscriptions"){typeof r.sequence_num=="number"&&(this.lastSeq===void 0||r.sequence_num>this.lastSeq)&&(this.lastSeq=r.sequence_num),this.conn.markSubscribed(),this.wasReconnecting&&(this.wasReconnecting=!1,this.reconnectedHandler?.());return}if(typeof r.sequence_num=="number"){let i=r.sequence_num;if(this.lastSeq!==void 0&&i<=this.lastSeq)return;this.lastSeq!==void 0&&i>this.lastSeq+1&&this.gapHandler?.(this.lastSeq+1,i),(this.lastSeq===void 0||i>this.lastSeq)&&(this.lastSeq=i)}if(r.channel==="heartbeats"){this.heartbeatHandler?.();return}let n=this.channel.wireName??this.channel.name;r.channel===n&&this.eventHandler(e)}}});function Ue(t,e){return Ir(t,e,"","","")}var Cr=I(()=>{"use strict";g();l();Ce()});var qe,as=I(()=>{"use strict";g();l();qe=class{snapshots=new Map;timestamps=new Map;now;constructor(e){this.now=e??Date.now}update(e,r){this.snapshots.set(e,r),this.timestamps.set(e,this.now())}get(e){return this.snapshots.get(e)}all(){return this.snapshots}isStale(e,r){let n=this.timestamps.get(e);return n===void 0?!1:this.now()-n>r}staleProducts(e,r){let n=new Set;for(let i of e)this.isStale(i,r)&&n.add(i);return n}hasSeen(e){return this.timestamps.has(e)}age(e){let r=this.timestamps.get(e);if(r!==void 0)return this.now()-r}}});function Nr(t,e,r){if(!r||t===0)return"";let n=t>0?Mt:Ft;return e?`${Lt}${n}`:n}function ls(t,e,r){if(!r)return"";let n=t==="bid"||t==="BUY"?Mt:Ft;return e?`${Lt}${n}`:n}var $,Lt,Mt,Ft,cs,B,_s,us,ds,gs,Ut=I(()=>{"use strict";g();l();$="\x1B[2m",Lt="\x1B[1m",Mt="\x1B[32m",Ft="\x1B[31m",cs="\x1B[33m",B="\x1B[0m",_s="\x1B[?25l",us="\x1B[?25h",ds="\x1B[?1049h",gs="\x1B[?1049l"});var qt,ps=I(()=>{"use strict";g();l();Ut();qt=class{out;inAltScreen=!1;cursorHidden=!1;scrollRegionSet=!1;cleanedUp=!1;resizeHandlers=[];sigwinchHandler=null;sigintHandler=null;sigtermHandler=null;stdinHandler=null;constructor(e){this.out=e??process.stdout}enterAltScreen(){this.out.write(ds),this.inAltScreen=!0}exitAltScreen(){this.out.write(gs),this.inAltScreen=!1}hideCursor(){this.out.write(_s),this.cursorHidden=!0}showCursor(){this.out.write(us),this.cursorHidden=!1}setScrollRegion(e,r){this.out.write(`\x1B[${e};${r}r`),this.scrollRegionSet=!0}resetScrollRegion(){this.out.write("\x1B[r"),this.scrollRegionSet=!1}moveTo(e,r){this.out.write(`\x1B[${e};${r}H`)}clearLine(){this.out.write("\x1B[K")}insertLine(){this.out.write("\x1B[L")}write(e){this.out.write(e)}get cols(){return this.out.columns??80}get rows(){return this.out.rows??24}onResize(e){this.resizeHandlers.push(e),this.sigwinchHandler||(this.sigwinchHandler=()=>{let r=this.cols,n=this.rows;for(let i of this.resizeHandlers)i(r,n)},process.on("SIGWINCH",this.sigwinchHandler))}installSignalHandlers(e){let r=e??(()=>process.exit(0));process.stdin.isTTY&&typeof process.stdin.setRawMode=="function"&&(process.stdin.setRawMode(!0),process.stdin.resume(),this.stdinHandler=n=>{n[0]===3&&(this.cleanup(),r())},process.stdin.on("data",this.stdinHandler)),this.sigintHandler=()=>{this.cleanup(),r()},this.sigtermHandler=()=>{this.cleanup(),r()},process.on("SIGINT",this.sigintHandler),process.on("SIGTERM",this.sigtermHandler)}cleanup(){this.cleanedUp||(this.cleanedUp=!0,process.stdin.isTTY&&typeof process.stdin.setRawMode=="function"&&process.stdin.setRawMode(!1),this.scrollRegionSet&&this.resetScrollRegion(),this.cursorHidden&&this.showCursor(),this.inAltScreen&&this.exitAltScreen(),this.out.write(B),this.removeListeners())}removeListeners(){this.stdinHandler&&(process.stdin.removeListener("data",this.stdinHandler),this.stdinHandler=null,process.stdin.isTTY&&process.stdin.pause()),this.sigwinchHandler&&(process.removeListener("SIGWINCH",this.sigwinchHandler),this.sigwinchHandler=null),this.sigintHandler&&(process.removeListener("SIGINT",this.sigintHandler),this.sigintHandler=null),this.sigtermHandler&&(process.removeListener("SIGTERM",this.sigtermHandler),this.sigtermHandler=null)}}});var oe,ms=I(()=>{"use strict";g();l();oe=class{flashes=new Map;offsets=new Map;now;constructor(e){this.now=e??Date.now}flash(e,r=600){this.flashes.set(e,this.now()+r)}isFlashing(e){let r=this.flashes.get(e);return r===void 0?!1:this.now()<r}expired(){let e=this.now(),r=[];for(let[n,i]of this.flashes)e>=i&&(r.push(n),this.flashes.delete(n),this.offsets.delete(n));return r}flashWithOffset(e,r,n=1500){let i=this.now()+n;this.flashes.set(e,i),this.offsets.set(e,{indexAtCreation:r,durationMs:n,expiry:i})}getRow(e,r,n){let i=this.offsets.get(e);if(!i)return null;if(this.now()>=i.expiry)return this.offsets.delete(e),null;let s=r-i.indexAtCreation-1;return n+s}clear(){this.flashes.clear(),this.offsets.clear()}}});function W(t,e){let r=ft(t);return r>=e?t.slice(0,t.length-(r-e)):t+" ".repeat(e-r)}function C(t,e){let r=ft(t);return r>=e?t.slice(0,t.length-(r-e)):" ".repeat(e-r)+t}function yt(t,e){let r="\u2500".repeat(t);return e?`${$}${r}${B}`:r}function Bt(t,e,r){let n=ft(t),i=ft(e);if(n+1+i>r){let a=r-i-1;return a>0?`${t.slice(0,a)} ${e}`:e.slice(0,r)}let o=r-n-i;return o<0?W(`${t} ${e}`,r):`${t}${" ".repeat(o)}${e}`}function zt(t,e){return e?t?`${Lt}\xB7${B}`:`${$}\xB7${B}`:""}function K(){let t=new Date,e=String(t.getHours()).padStart(2,"0"),r=String(t.getMinutes()).padStart(2,"0"),n=String(t.getSeconds()).padStart(2,"0");return`${e}:${r}:${n}`}var ae=I(()=>{"use strict";g();l();Ge();Ut()});function j(t){let e=Math.abs(t);return e>=1e3?t.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}):e>=1?t.toFixed(2):t.toFixed(4)}function Wt(t){let e=Math.abs(t);return e>=100?t.toFixed(1):e>=10?t.toFixed(2):e>=1?t.toFixed(3):e>=.01?t.toFixed(4):e>=1e-4?t.toFixed(6):t===0?"0":t.toFixed(8)}function fs(t){return t>=1e9?`${(t/1e9).toFixed(1)}B`:t>=1e6?`${(t/1e6).toFixed(0)}M`:t>=1e3?`${(t/1e3).toFixed(0)}K`:t.toFixed(0)}function ys(t){return`${t>=0?"+":""}${t.toFixed(2)}%`}function bs(t){let e=new Date(t);if(isNaN(e.getTime()))return t;let r=String(e.getHours()).padStart(2,"0"),n=String(e.getMinutes()).padStart(2,"0"),i=String(e.getSeconds()).padStart(2,"0"),s=String(e.getMilliseconds()).padStart(3,"0");return`${r}:${n}:${i}.${s}`}var Be=I(()=>{"use strict";g();l()});function Es(t){let e=[],r=0;for(let n of gc){if(r+n.width+1>t){let i=t-r-1;i>=4&&n.key==="id"&&e.push({...n,width:i});break}e.push(n),r+=n.width+1}return e}function Is(){return{events:[],positions:new Map,openOrders:new Set,totalFees:0,lastClock:K(),netCash:0,fillCount:0,accounted:new Map,prependCount:0,heartbeat:!1,updateCount:0}}function lc(t){let e=t.order_configuration;if(e)for(let r of Object.values(e)){if(r&&typeof r=="object"&&"base_size"in r)return String(r.base_size);if(r&&typeof r=="object"&&"quote_size"in r)return`$${String(r.quote_size)}`}}function pc(t,e){let r=e.creation_time?Date.parse(e.creation_time):NaN;if(Number.isNaN(r))return 0;for(let n=0;n<t.length;n++){let i=t[n].creation_time?Date.parse(t[n].creation_time):NaN;if(!Number.isNaN(i)&&i<r)return n}return t.length}function Gr(t,e,r="live"){let n=t.events;if(!n)return{inserts:[],updates:[]};let i=[],s=[];for(let o of n){let a=o.orders;if(a)for(let c of a){let d={order_id:String(c.order_id??""),status:String(c.status??""),product_id:String(c.product_id??""),order_side:String(c.order_side??c.side??""),order_type:c.order_type?String(c.order_type):void 0,average_filled_price:String(c.average_filled_price??c.avg_price??"0"),total_fees:String(c.total_fees??"0"),filled_size:String(c.filled_size??c.cumulative_quantity??"0"),base_size:lc(c),creation_time:c.creation_time?String(c.creation_time):c.created_time?String(c.created_time):void 0},p=e.events.findIndex(_=>_.order_id===d.order_id);if(p>=0){let _=e.events[p],u=_.status!==d.status||_.filled_size!==d.filled_size||_.total_fees!==d.total_fees||_.average_filled_price!==d.average_filled_price;_.status=d.status,_.average_filled_price=d.average_filled_price,_.filled_size=d.filled_size,_.total_fees=d.total_fees,u&&(hs(e,d),s.push(_));continue}r==="backfill"?e.events.splice(pc(e.events,d),0,d):e.events.unshift(d),e.prependCount++,hs(e,d),i.push(d),e.events.length>1e4&&e.events.pop()}}return{inserts:i,updates:s}}function hs(t,e){t.updateCount++,t.lastClock=K();let r=e.status.toUpperCase();r==="OPEN"||r==="PENDING"?t.openOrders.add(e.order_id):t.openOrders.delete(e.order_id);let n=parseFloat(e.total_fees??"0")||0,i=parseFloat(e.filled_size??"0")||0,s=parseFloat(e.average_filled_price??"0")||0,o=i*s,a=t.accounted.get(e.order_id)??{fees:0,size:0,value:0},c=n-a.fees,d=i-a.size,p=o-a.value;(d!==0||c!==0)&&(a.size===0&&i>0&&t.fillCount++,t.totalFees+=c,e.order_side==="BUY"?(t.netCash-=p,t.positions.set(e.product_id,(t.positions.get(e.product_id)??0)+d)):(t.netCash+=p,t.positions.set(e.product_id,(t.positions.get(e.product_id)??0)-d)),t.accounted.set(e.order_id,{fees:n,size:i,value:o}))}function mc(t,e,r,n,i){let s=e.order_side==="BUY"?"BUY":"SELL",o=ls(s,n,i),a=e.status.toUpperCase(),c=i?B:"",d=parseFloat(e.average_filled_price??"0"),p=parseFloat(e.filled_size??"0");switch(t){case"time":return W(bs(e.creation_time??new Date().toISOString()),r);case"status":return`${(a==="OPEN"||a==="PENDING")&&i?cs:""}${W(a,r)}${c}`;case"product":return W(e.product_id,r);case"side":return`${o}${W(s,r)}${c}`;case"size":{let _=p>0?Wt(p):e.base_size??"-";return`${o}${C(_,r)}${c}`}case"price":return`${o}${C(d>0?j(d):"-",r)}${c}`;case"fee":{let _=parseFloat(e.total_fees??"0");return C(_>0?j(_):"-",r)}case"id":return`${i?$:""}${W(e.order_id.slice(0,r),r)}${c}`;default:return W("",r)}}function ce(t,e,r,n=80){return Es(n).map(i=>mc(i.key,t,i.width,e,r)).join(" ")}function fc(t,e=80){let r=new Set(["size","price","fee"]),i=Es(e).map(s=>r.has(s.key)?C(s.header,s.width):W(s.header,s.width)).join(" ");return t?`${$}${i}${B}`:i}function yc(t,e,r){let n=t.netCash>=0?r?Mt:"":r?Ft:"",i=r?B:"",s=`Fills:${t.fillCount}`,o=`Open:${t.openOrders.size}`,a=`Fees:${j(t.totalFees)}`,c=`Net:${t.netCash>=0?"+":""}${j(t.netCash)}`,d=`${n}${c}${i}`,_=`${zt(t.heartbeat,r)} ${t.lastClock}`,u=`\xB7 ${t.lastClock}`,f=`${s} ${o} ${a} ${c}`,O=`${s} ${o} ${a} ${d}`,E=new Map;for(let[R,P]of t.positions){if(Math.abs(P)<1e-9)continue;let V=(R.match(/-/g)??[]).length===1?R.slice(0,R.indexOf("-")):R;E.set(V,(E.get(V)??0)+P)}let x=[],w=[];for(let[R,P]of E){if(Math.abs(P)<1e-9)continue;let H=`${R}:${Wt(P)}`;x.push(H),w.push(H)}let N=e-f.length-u.length-6,F="";if(x.length>0&&N>8){let R="",P=0,H=0;for(let V=0;V<x.length;V++){let Q=H>0?" ":"";if(P+Q.length+w[V].length>N){let Ht=x.length-H;Ht>0&&(R+=` +${Ht}`);break}R+=Q+x[V],P+=Q.length+w[V].length,H++}F=R}let Y=F?`${O} ${F}`:O;return Bt(Y,_,e)}function vs(t,e,r,n,i){let s=i??e.events,o=t.cols,a=t.rows,c=a,d=a-1,p=a-2;n.inserts.forEach((_,u)=>{r.flashWithOffset(_.order_id,e.prependCount-1-u,1500),t.moveTo(ze,1),t.insertLine(),t.write(ce(_,!0,!0,t.cols)+"\x1B[K")});for(let _ of n.updates){let u=s.indexOf(_);if(u>=0){let f=ze+u;f<=p&&(r.flash(_.order_id,1500),t.moveTo(f,1),t.write(ce(_,!0,!0,t.cols)+"\x1B[K"))}}for(let _ of r.expired()){let u=s.findIndex(f=>f.order_id===_);if(u>=0){let f=ze+u;f<=p&&(t.moveTo(f,1),t.write(ce(s[u],!1,!0,t.cols)+"\x1B[K"))}}t.moveTo(d,1),t.write(yt(o,!0)),t.moveTo(c,1),t.write(yc(e,o-1,!0)+"\x1B[K")}function Dr(t){t.enterAltScreen(),t.hideCursor();let e=t.rows;t.setScrollRegion(ze,e-2),t.moveTo(1,1),t.write(fc(!0,t.cols)+"\x1B[K"),t.moveTo(2,1),t.write(yt(t.cols,!0))}function We(t,e,r){return{_ch:"user",_seq:e,_ts:r,order_id:t.order_id,status:t.status,product_id:t.product_id,side:t.order_side,filled_size:t.filled_size??null,price:t.average_filled_price??null,fees:t.total_fees??null}}function ks(t,e,r){return JSON.stringify(We(t,e,r))}var ze,gc,Os=I(()=>{"use strict";g();l();ae();Ut();Be();ze=3,gc=[{header:"TIME",width:13,key:"time"},{header:"STATUS",width:10,key:"status"},{header:"PRODUCT",width:10,key:"product"},{header:"SIDE",width:5,key:"side"},{header:"SIZE",width:12,key:"size"},{header:"PRICE",width:12,key:"price"},{header:"FEE",width:8,key:"fee"},{header:"ORDER ID",width:12,key:"id"}]});function Rs(t,e,r,n=8){let i=r-e;if(i<=0)return"\u2500".repeat(n);let s=Math.max(0,Math.min(1,(t-e)/i)),o=Math.round(s*(n-1)),a="";for(let c=0;c<n;c++)a+=c===o?"\u25CF":"\u2500";return a}function Ps(t,e,r){if(e<=0||t<=0)return"";let n=Math.max(0,Math.round(t/e*r));return"\u2588".repeat(n)}var Lr=I(()=>{"use strict";g();l()});function xs(t){let e=[],r=0;for(let n of Ec){if(r+n.width+1>t)break;e.push(n),r+=n.width+1}return e}function ws(){return{products:new Map,prevPrices:new Map,productOrder:[],heartbeat:!1,updateCount:0,lastClock:K()}}function As(t,e){let r=t.events;if(!r)return[];let n=[];for(let i of r){let s=i.tickers;if(s)for(let o of s){let a={product_id:String(o.product_id??""),price:String(o.price??"0"),volume_24_h:String(o.volume_24_h??"0"),price_percent_chg_24_h:String(o.price_percent_chg_24_h??"0"),best_bid:String(o.best_bid??"0"),best_bid_quantity:String(o.best_bid_quantity??"0"),best_ask:String(o.best_ask??"0"),best_ask_quantity:String(o.best_ask_quantity??"0"),high_24_h:String(o.high_24_h??"0"),low_24_h:String(o.low_24_h??"0")},c=e.prevPrices.get(a.product_id),d=parseFloat(a.price),p=0;c!==void 0&&(d>c?p=1:d<c&&(p=-1)),e.prevPrices.set(a.product_id,d),e.products.set(a.product_id,a),e.productOrder.includes(a.product_id)||e.productOrder.push(a.product_id),e.updateCount++,e.lastClock=K(),n.push({ticker:a,direction:p})}}return n}function Ic(t,e,r,n,i,s){let o=parseFloat(e.price),a=s?B:"";switch(t){case"symbol":return W(e.product_id,r);case"price":return`${Nr(n,i,s)}${C(j(o),r)}${a}`;case"pct":{let c=parseFloat(e.price_percent_chg_24_h),d=c>0?1:c<0?-1:0;return`${Nr(d,!1,s)}${C(ys(c),r)}${a}`}case"bid":return C(j(parseFloat(e.best_bid)),r);case"ask":return C(j(parseFloat(e.best_ask)),r);case"bidSz":return`${s?$:""}${C(Wt(parseFloat(e.best_bid_quantity)),r)}${a}`;case"askSz":return`${s?$:""}${C(Wt(parseFloat(e.best_ask_quantity)),r)}${a}`;case"low":return`${s?$:""}${C(j(parseFloat(e.low_24_h)),r)}${a}`;case"high":return`${s?$:""}${C(j(parseFloat(e.high_24_h)),r)}${a}`;case"range":return W(Rs(o,parseFloat(e.low_24_h),parseFloat(e.high_24_h),r),r);case"vol":return`${s?$:""}${C(fs(parseFloat(e.volume_24_h)),r)}${a}`;default:return W("",r)}}function Ss(t,e,r,n,i=80){return xs(i).map(o=>Ic(o.key,t,o.width,e,r,n)).join(" ")}function vc(t,e=80){let n=xs(e).map(i=>i.key==="symbol"||i.key==="range"?W(i.header,i.width):C(i.header,i.width)).join(" ");return t?`${$}${n}${B}`:n}function kc(t,e,r){let n=`${t.products.size} product${t.products.size!==1?"s":""}`,s=`${zt(t.heartbeat,r)} ${t.lastClock}`;return Bt(n,s,e)}function Mr(t){t.enterAltScreen(),t.hideCursor(),t.moveTo(bc,1),t.write(vc(!0,t.cols)+"\x1B[K"),t.moveTo(hc,1),t.write(yt(t.cols,!0))}function Cs(t,e,r,n,i){let s=t.cols,o=t.rows,a=o,c=o-1;for(let{ticker:d,direction:p}of n){let _=e.productOrder.indexOf(d.product_id);if(_<0)continue;let u=Ts+_;if(u>=c)continue;let f=i?.has(d.product_id)??!1,O=!f&&r.isFlashing(d.product_id);t.moveTo(u,1);let E=Ss(d,f?0:p,O,!0,s);t.write((f?$+E+B:E)+"\x1B[K")}for(let d of r.expired()){let p=e.productOrder.indexOf(d);if(p<0)continue;let _=Ts+p;if(_>=c)continue;let u=e.products.get(d);u&&(t.moveTo(_,1),t.write(Ss(u,0,!1,!0,s)+"\x1B[K"))}t.moveTo(c,1),t.write(yt(s,!0)),t.moveTo(a,1),t.write(kc(e,s-1,!0)+"\x1B[K")}function Fr(t,e,r){return{_ch:"ticker",_seq:e,_ts:r,product_id:t.product_id,price:t.price,pct_24h:t.price_percent_chg_24_h,bid:t.best_bid,bid_size:t.best_bid_quantity,ask:t.best_ask,ask_size:t.best_ask_quantity,volume:t.volume_24_h,high:t.high_24_h,low:t.low_24_h}}function Ns(t,e,r){return JSON.stringify(Fr(t,e,r))}var bc,hc,Ts,Ec,Gs=I(()=>{"use strict";g();l();ae();Ut();Be();Lr();bc=1,hc=2,Ts=3,Ec=[{header:"SYMBOL",width:10,key:"symbol"},{header:"PRICE",width:12,key:"price"},{header:"%24h",width:8,key:"pct"},{header:"BID",width:11,key:"bid"},{header:"ASK",width:11,key:"ask"},{header:"LOW",width:11,key:"low"},{header:"RANGE",width:10,key:"range"},{header:"HIGH",width:11,key:"high"},{header:"BIDSZ",width:7,key:"bidSz"},{header:"ASKSZ",width:7,key:"askSz"},{header:"VOL",width:6,key:"vol"}]});function Ls(t,e=0){return{productId:t,bids:new Map,asks:new Map,heartbeat:!1,updateCount:0,msgCount:0,lastMsgTime:Date.now(),msgRate:0,depth:e,lastClock:K()}}function Ms(t,e){let r=t.events;if(!r)return;e.msgCount++;let n=Date.now(),i=(n-e.lastMsgTime)/1e3;i>=1&&(e.msgRate=Math.round(e.msgCount/i),e.msgCount=0,e.lastMsgTime=n);for(let s of r){let o=s.type,a=s.updates;if(o==="snapshot"&&(e.bids.clear(),e.asks.clear()),!!a){for(let c of a){let d=String(c.side??"").toLowerCase(),p=parseFloat(String(c.price_level??"0")),_=parseFloat(String(c.new_quantity??"0"));if(p<=0)continue;let u=d==="bid"?e.bids:e.asks;_<=0?u.delete(p):u.set(p,_)}e.updateCount++,e.lastClock=K()}}}function $e(t){let e=[];for(let[r,n]of t.bids)e.push({price:r,size:n});return e.sort((r,n)=>n.price-r.price),e}function Ve(t){let e=[];for(let[r,n]of t.asks)e.push({price:r,size:n});return e.sort((r,n)=>r.price-n.price),e}function Ds(t,e,r,n,i,s,o){let a=o?i==="bid"?Mt:Ft:"",c=o?B:"",d=Ps(r,n,s),p=`${a}${d}${c}`;return[`${a}${C(j(t),bt[0])}${c}`,C(e.toFixed(4),bt[1]),C(r.toFixed(4),bt[2]),p].join(" ")}function Pc(t,e,r){let n=Ve(t),i=$e(t),s=n.length>0?n[0].price:0,o=i.length>0?i[0].price:0,a=s-o,c=(s+o)/2,d=c>0?a/c*100:0,p=c>0?` Spread: ${j(a).padStart(10)} (${d.toFixed(3).padStart(6)}%) Mid: ${j(c).padStart(12)}`:" Waiting for data...",_=r?$:"",u=r?B:"";return`${_}${W(p,e)}${u}`}function Tc(t,e,r){let n=Rc.map((c,d)=>d===3?W(c,bt[d]):C(c,bt[d])).join(" "),i=r?$:"",s=r?Lt:"",o=r?B:"",a=`${s}${t.productId}${o}`;return`${W(a,e)}
|
|
53
|
+
${i}${n}${o}`}function Sc(t,e,r){let n=$e(t).reduce((p,_)=>p+_.size,0),i=Ve(t).reduce((p,_)=>p+_.size,0),s=i>0?(n/i).toFixed(2):"-",a=`${t.depth?`Depth:${t.depth} `:""}B/A:${s} Rate:${t.msgRate}/s`,d=`${zt(t.heartbeat,r)} ${t.lastClock}`;return Bt(a,d,e)}function Ur(t,e){t.enterAltScreen(),t.hideCursor(),qr(t,e)}function qr(t,e){let r=t.cols,n=t.rows;if(n<4)return;let i=bt[0]+bt[1]+bt[2]+3,s=Math.max(4,r-i),o=Ve(e),a=$e(e),c=n-1,d=n,p=Math.max(0,n-4),_=Math.floor(p/2),u=p>_*2||_>0,f=e.depth?Math.min(_,e.depth):_,O=o.slice(0,f),E=a.slice(0,f),x=0,w=[];for(let P of O)x+=P.size,w.push(x);let N=0,F=[];for(let P of E)N+=P.size,F.push(N);let Y=Math.max(x,N),R=1;t.moveTo(R,1),t.write(Tc(e,r,!0)+"\x1B[K"),R=Oc;for(let P=0;P<f&&R<c;P++,R++)if(t.moveTo(R,1),P<O.length){let H=O.length-1-P;t.write(Ds(O[H].price,O[H].size,w[H],Y,"ask",s,!0)+"\x1B[K")}else t.clearLine();u&&R<c&&(t.moveTo(R,1),t.write(Pc(e,r,!0)+"\x1B[K"),R++);for(let P=0;P<f&&R<c;P++,R++)t.moveTo(R,1),P<E.length?t.write(Ds(E[P].price,E[P].size,F[P],Y,"bid",s,!0)+"\x1B[K"):t.clearLine();for(;R<c;)t.moveTo(R,1),t.clearLine(),R++;t.moveTo(c,1),t.write(yt(r,!0)),t.moveTo(d,1),t.write(Sc(e,r-1,!0)+"\x1B[K")}function Br(t,e,r){let n=$e(t).map(a=>({price:a.price,size:a.size})),i=Ve(t).map(a=>({price:a.price,size:a.size})),s=i.length>0?i[0].price:0,o=n.length>0?n[0].price:0;return{_ch:"level2",_seq:e,_ts:r,product_id:t.productId,spread:s-o,mid:(s+o)/2,bids:n,asks:i}}function Fs(t,e,r){return JSON.stringify(Br(t,e,r))}var Oc,bt,Rc,Us=I(()=>{"use strict";g();l();ae();Ut();Be();Lr();Oc=3,bt=[14,12,12,16],Rc=["PRICE","SIZE","TOTAL","DEPTH"]});function qs(t,e,r,n,i){return new zr(t,e,r,n,i)}function Bs(t,e,r){return new Wr(t,e,r)}function zs(t,e,r,n){return new $r(t,e,r,n)}var zr,Wr,$r,Ws=I(()=>{"use strict";g();l();Me();Cr();ps();ms();ae();Os();Gs();Us();Te();zr=class{productIds=[];screen;refreshJWT;state=Is();flash=new oe;queryFilter;context;jwt;until;liveness=!1;connected=!1;constructor(e,r,n,i,s){this.context=r,this.jwt=n,this.until=s,this.queryFilter=e.flags.query,e.isTTY&&!e.untilActive&&(this.screen=new qt(e.out),Dr(this.screen),this.screen.onResize(()=>{Dr(this.screen),this.repaintFrame()})),i.requiresAuth&&(this.refreshJWT=()=>this.freshJWT())}freshJWT(){let e=this.context.env;return e?.auth?.key_id&&e?.auth?.key_secret?Ue(e.auth.key_id,e.auth.key_secret):this.jwt}matchesFilter(e){let r=this.queryFilter;return r?!(r.status&&e.status.toUpperCase()!==String(r.status).toUpperCase()||r.product_ids&&!String(r.product_ids).split(",").includes(e.product_id)||r.side&&e.order_side.toUpperCase()!==String(r.side).toUpperCase()):!0}visibleEvents(){return this.queryFilter?this.state.events.filter(e=>this.matchesFilter(e)):void 0}syncHeartbeat(){this.state.heartbeat=this.connected&&this.liveness}render(e){this.screen&&(this.syncHeartbeat(),vs(this.screen,this.state,this.flash,e,this.visibleEvents()))}repaintFrame(){if(!this.screen)return;let e=this.queryFilter?this.state.events.filter(i=>this.matchesFilter(i)):this.state.events,r=this.screen.rows-4,n=Math.min(e.length,r);for(let i=n-1;i>=0;i--)this.screen.moveTo(3+i,1),this.screen.write(ce(e[i],!1,!0,this.screen.cols)+"\x1B[K");for(let i=n;i<r;i++)this.screen.moveTo(3+i,1),this.screen.write("\x1B[K");this.render({inserts:[],updates:[]})}onData(e,r,n){let i=this.queryFilter?this.visibleEvents().map(c=>c.order_id):void 0,s=Gr(e,this.state);this.liveness=!this.liveness;let o={inserts:s.inserts.filter(c=>this.matchesFilter(c)),updates:s.updates.filter(c=>this.matchesFilter(c))};if(i){let c=this.visibleEvents().map(p=>p.order_id);c.length!==i.length||c.some((p,_)=>p!==i[_])?this.repaintFrame():this.render(o)}else this.render(o);return[...o.inserts,...o.updates].map(c=>({obj:We(c,r,n),line:ks(c,r,n)}))}onHeartbeat(){this.liveness=!this.liveness,this.state.lastClock=K(),this.render({inserts:[],updates:[]})}onConnState(e){this.connected=e===q.SUBSCRIBED,this.repaintFrame()}onGap(){this.backfill().catch(()=>{})}onReconnected(){this.backfill().catch(()=>{})}setup(){return this.backfill()}cleanup(){this.screen?.cleanup()}async backfill(){try{let e=await Gt("orders_list",{query:{limit:100,...this.queryFilter}},this.context);if(e.status<400&&e.data?.orders){let r=e.data.orders;for(let n of r.reverse()){let s=Gr({events:[{orders:[n]}]},this.state,"backfill");if(this.until.active)for(let o of[...s.inserts,...s.updates]){let a=String(n.created_time??new Date().toISOString());if(this.until.check(We(o,0,a)))return}}}}catch{}this.repaintFrame()}};Wr=class{productIds;screen;state=ws();flash=new oe;until;liveness=!1;connected=!1;constructor(e,r,n){this.until=n,this.productIds=r,e.isTTY&&!e.untilActive&&(this.screen=new qt(e.out),Mr(this.screen),this.screen.onResize(()=>{Mr(this.screen),this.repaintFrame()}))}syncHeartbeat(){this.state.heartbeat=this.connected&&this.liveness}render(e){this.screen&&(this.syncHeartbeat(),Cs(this.screen,this.state,this.flash,e,this.until.active?this.until.stale:void 0))}repaintFrame(){if(!this.screen)return;let e=this.state.productOrder.map(r=>this.state.products.get(r)).filter(r=>!!r).map(r=>({ticker:r,direction:0}));this.render(e)}onData(e,r,n){let i=As(e,this.state);this.liveness=!this.liveness;for(let{ticker:s}of i)this.flash.flash(s.product_id,600);return this.render(i),i.map(({ticker:s})=>({obj:Fr(s,r,n),line:Ns(s,r,n)}))}onHeartbeat(){this.liveness=!this.liveness,this.state.lastClock=K(),this.render([])}onConnState(e){this.connected=e===q.SUBSCRIBED,this.render([])}onGap(){}onReconnected(){}async setup(){}cleanup(){this.screen?.cleanup()}};$r=class{productIds;screen;state;productId;liveness=!1;connected=!1;constructor(e,r,n,i){this.productId=r,this.productIds=[r],this.state=Ls(r,e.flags.depth??0),e.isTTY&&!e.untilActive&&(this.screen=new qt(e.out),Ur(this.screen,this.state),this.screen.onResize(()=>{Ur(this.screen,this.state),this.render()}))}syncHeartbeat(){this.state.heartbeat=this.connected&&this.liveness}render(){this.screen&&(this.syncHeartbeat(),qr(this.screen,this.state))}onData(e,r,n){return Ms(e,this.state),this.liveness=!this.liveness,this.render(),[{obj:Br(this.state,r,n),line:Fs(this.state,r,n)}]}onHeartbeat(){this.liveness=!this.liveness,this.state.lastClock=K(),this.render()}onConnState(e){this.connected=e===q.SUBSCRIBED,this.render()}onGap(){return this.state.bids.clear(),this.state.asks.clear(),this.render(),{resubscribe:[this.productId]}}onReconnected(){}async setup(){}cleanup(){this.screen?.cleanup()}}});var $s={};jt($s,{applyJQ:()=>Vr});import{execFileSync as xc}from"node:child_process";function Vr(t,e){try{return xc("jq",["-r",e],{input:t,encoding:"utf8",maxBuffer:10*1024*1024,env:ar()}).trimEnd()}catch(r){if(r.code==="ENOENT")throw new Error("jq is not installed. Install it: https://jqlang.github.io/jq/download/");let n=(r.stderr??r.message??"").toString().trim();throw new Error(`jq: ${n}`)}}var Hr=I(()=>{"use strict";g();l();tt()});var jr={};jt(jr,{UntilController:()=>$t,__test:()=>Dc,startWatch:()=>Gc,surfaceForChannel:()=>ht});function Ac(t){return wc.find(e=>e.id===t)}function ht(t){switch(t.name){case"user":return"blotter";case"ticker":return"watchlist";case"level2":return"ladder";default:return null}}async function Nc(t,e){if(!e.requiresAuth)return;let n=t.env?.auth;if(!n)throw new Error("WebSocket channel requires authentication. Run: coinbase env <name> --key-file key.json");if(n.type==="oauth")throw new Error(`The --watch blotter requires CDP API key auth (WebSocket does not support OAuth).
|
|
54
|
+
Set up a CDP key: coinbase env <name> --key-file key.json`);if(n.type==="cdp_key"&&n.key_id&&n.key_secret)return Ue(n.key_id,n.key_secret);throw new Error("Unsupported auth type for WebSocket")}async function Gc(t,e,r,n){let i=st(t);if(!i)throw new Error(`--watch is not supported for "${t.replace(/_/g," ")}"`);let s=ht(i);if(!s)throw new Error(`--watch is not yet implemented for channel "${i.name}"`);if(n.until){let c;try{c=xr(n.until)}catch(_){throw new Error(`Invalid --until predicate: ${_.message}`)}let d=Ac(t);if(d?.watchFields){let _=is(c,d.watchFields);if(_.length>0){let u=Object.keys(d.watchFields).join(", ");throw new Error(_.map(f=>f.message).join(`
|
|
55
55
|
`)+`
|
|
56
|
-
Available fields: ${u}`)}}let p=
|
|
57
|
-
Watching: ${e.join(", ")}`)}}let o=await
|
|
58
|
-
`),onStateChange:p=>{p===q.FAILED&&n.onFailed(),i.onConnState(p)},onDisconnect:()=>n.onDisconnect(),onReconnect:()=>n.onReconnect(),onReconnected:()=>i.onReconnected(),refreshJWT:i.refreshJWT}),c.connect(),c.subscribe(i.productIds,e);let d=await
|
|
56
|
+
Available fields: ${u}`)}}let p=ie(c);if(p.length>0&&e.length>0){let _=p.filter(u=>!e.includes(u));if(_.length>0)throw new Error(`Predicate references product${_.length>1?"s":""} not in watch: ${_.join(", ")}
|
|
57
|
+
Watching: ${e.join(", ")}`)}}let o=await Nc(r,i),a=!!process.stdout.isTTY;await Mc(n),s==="blotter"?await Hs(i,o,r,n,a):s==="watchlist"?await js(i,e,o,n,a):s==="ladder"&&await Ks(i,e,o,n,a)}async function je(t,e,r,n,i,s){let o=n.start();await i.setup();let a=0,c;c=new Fe({channel:t,WebSocketClass:s,onEvent:p=>{let _=p;a=_.sequence_num??a;let u=String(_.timestamp??new Date().toISOString()),f=i.onData(_,a,u);if(f.length!==0){if(!i.screen&&!n.active)for(let O of f)Qs(O.line,r);if(n.active){for(let O of f)if(n.check(O.obj))return}}},onHeartbeat:()=>i.onHeartbeat(),onSequenceGap:()=>{let p=i.onGap();p&&(c.unsubscribe(p.resubscribe),c.subscribe(p.resubscribe,i.refreshJWT?i.refreshJWT():e))},onError:i.screen?void 0:p=>process.stderr.write(`ws error: ${p}
|
|
58
|
+
`),onStateChange:p=>{p===q.FAILED&&n.onFailed(),i.onConnState(p)},onDisconnect:()=>n.onDisconnect(),onReconnect:()=>n.onReconnect(),onReconnected:()=>i.onReconnected(),refreshJWT:i.refreshJWT}),c.connect(),c.subscribe(i.productIds,e);let d=await Lc(o,i.screen);c.close(),Ys(d,i,r,n),d===null&&process.exit(process.exitCode??0)}async function Hs(t,e,r,n,i,s,o){let a=new $t(n),c=qs({isTTY:i,untilActive:a.active,flags:n,out:s?.out},r,e,t,a);await je(t,e,n,a,c,o)}async function js(t,e,r,n,i,s,o){if(e.length===0)throw new Error("--watch requires at least one product_id (e.g. BTC-USD)");let a=new $t(n),c=Bs({isTTY:i,untilActive:a.active,flags:n,out:s?.out},e,a);await je(t,r,n,a,c,o)}async function Ks(t,e,r,n,i,s,o){if(e.length===0)throw new Error("--watch requires a product_id (e.g. BTC-USD)");if(e.length>1)throw new Error("--watch book supports a single product_id; got: "+e.join(", "));let a=e[0],c=new $t(n),d=zs({isTTY:i,untilActive:c.active,flags:n,out:s?.out},a,r,c);await je(t,r,n,c,d,o)}function Lc(t,e){return new Promise(r=>{let n=()=>{},i=s=>{n(),r(s)};if(e)e.installSignalHandlers(()=>i(null));else{let s=()=>i(null),o=()=>i(null);n=()=>{process.off("SIGINT",s),process.off("SIGTERM",o)},process.on("SIGINT",s),process.on("SIGTERM",o)}t.then(i)})}function Ys(t,e,r,n){if(e.cleanup(),n?.cleanup(),!!t)switch(t.type){case"matched":Qs(JSON.stringify(t.event),r??{}),process.exitCode=0;break;case"timeout":process.stderr.write(`error: --until timed out
|
|
59
59
|
`),process.exitCode=124;break;case"failed":process.stderr.write(`error: WebSocket connection failed permanently
|
|
60
60
|
`),process.exitCode=2;break;case"disconnect_budget_exceeded":process.stderr.write(`error: cumulative disconnection exceeded ${Math.round(t.totalMs/1e3)}s
|
|
61
|
-
`),process.exitCode=2;break}}function
|
|
61
|
+
`),process.exitCode=2;break}}function Qs(t,e){if(e.jq)try{let{applyJQ:r}=He,n=r(new TextEncoder().encode(t),e.jq);process.stdout.write(n+`
|
|
62
62
|
`)}catch(r){process.stderr.write(`jq error: ${r.message??r}
|
|
63
63
|
`)}else process.stdout.write(t+`
|
|
64
|
-
`)}async function
|
|
65
|
-
`));for(let n of this.requiredProducts)if(this.signals.hasSeen(n)&&this.signals.isStale(n
|
|
66
|
-
`)),!1;return Dt(this.predicate,e,this.signals.all())?(this.settle({type:"matched",event:e}),!0):!1}onDisconnect(){!this.active||this.settled||(this.disconnectStart=Date.now())}onReconnect(){!this.active||this.settled||(this.disconnectStart!==null&&(this.cumulativeDisconnectMs+=Date.now()-this.disconnectStart,this.disconnectStart=null),this.cumulativeDisconnectMs>
|
|
64
|
+
`)}async function Mc(t){if(t.jq&&!He){He=await Promise.resolve().then(()=>(Hr(),$s));try{let{applyJQ:e}=He;e(new TextEncoder().encode("{}"),t.jq)}catch(e){throw new Error(`Invalid --jq expression: ${e.message??e}`)}}}var wc,Cc,Vs,$t,Dc,He,_e=I(()=>{"use strict";g();l();se();os();Me();Cr();as();wr();Ct();Ws();wc=[...et.flatMap(t=>t.actions),...Object.values(rt)];Cc=300*1e3,Vs=3e4,$t=class{predicate;timeoutMs;timeoutTimer=null;disconnectStart=null;cumulativeDisconnectMs=0;resolve=null;settled=!1;signals;requiredProducts;reportedStale=new Set;constructor(e,r){this.predicate=e.until?xr(e.until):null,this.timeoutMs=e.untilTimeout?e.untilTimeout*1e3:null,this.requiredProducts=this.predicate?[...new Set(ie(this.predicate))]:[],this.signals=r??new qe}get active(){return this.predicate!==null}get stale(){return this.signals.staleProducts(this.requiredProducts,Vs)}start(){return new Promise(e=>{this.resolve=e,this.active&&this.timeoutMs!==null&&(this.timeoutTimer=setTimeout(()=>{this.settle({type:"timeout"})},this.timeoutMs))})}check(e){if(!this.predicate||this.settled)return!1;let r=e.product_id;r&&(this.signals.update(r,e),this.reportedStale.delete(r)&&process.stderr.write(`notice: ${r} recovered
|
|
65
|
+
`));for(let n of this.requiredProducts)if(this.signals.hasSeen(n)&&this.signals.isStale(n,Vs))return this.reportedStale.has(n)||(this.reportedStale.add(n),process.stderr.write(`warning: ${n} stale (no update for ${Math.round(this.signals.age(n)/1e3)}s)
|
|
66
|
+
`)),!1;return Dt(this.predicate,e,this.signals.all())?(this.settle({type:"matched",event:e}),!0):!1}onDisconnect(){!this.active||this.settled||(this.disconnectStart=Date.now())}onReconnect(){!this.active||this.settled||(this.disconnectStart!==null&&(this.cumulativeDisconnectMs+=Date.now()-this.disconnectStart,this.disconnectStart=null),this.cumulativeDisconnectMs>Cc&&this.settle({type:"disconnect_budget_exceeded",totalMs:this.cumulativeDisconnectMs}))}onFailed(){this.settled||this.settle({type:"failed"})}cleanup(){this.timeoutTimer&&(clearTimeout(this.timeoutTimer),this.timeoutTimer=null)}settle(e){this.settled||(this.settled=!0,this.cleanup(),this.resolve?.(e))}};Dc={runSurface:je,runBlotter:Hs,runWatchlist:js,runLadder:Ks,handleResult:Ys};He=null});var Ke={};jt(Ke,{bodyBytes:()=>Hc,hasBody:()=>Vc,isFieldArg:()=>Kc,parseFields:()=>Wc,setNested:()=>Qr});import{readFileSync as Fc,openSync as Uc,readSync as qc,closeSync as Bc}from"node:fs";function Wc(t,e=zc){let r={body:{},query:new URLSearchParams,headers:{},rawBody:null};for(let n of t)if(n==="-")r.rawBody=e.readStdin();else if(n.startsWith("@"))r.rawBody=e.readFile(n.slice(1));else if($c(n)){let i=n.indexOf(":");r.headers[n.slice(0,i)]=n.slice(i+1).trim()}else{let i=n.indexOf("=");if(i<=0)throw new Error(`unrecognized argument: ${n} (use key=value, key:=json, key==query, or Header:value)`);if(n[i-1]===":"){let s=n.slice(0,i-1);try{Qr(r.body,s,JSON.parse(n.slice(i+1)))}catch(o){throw new Error(`invalid JSON in ${s}: ${o.message}`)}}else n[i+1]==="="?r.query.append(n.slice(0,i),n.slice(i+2)):Qr(r.body,n.slice(0,i),n.slice(i+1))}return r}function $c(t){let e=t.indexOf(":");return e<=0||t.slice(0,e).includes("=")?!1:t[0]>="A"&&t[0]<="Z"}function Vc(t){return Object.keys(t.body).length>0||t.rawBody!==null}function Hc(t){return t.rawBody?t.rawBody:Object.keys(t.body).length===0?null:new TextEncoder().encode(JSON.stringify(t.body))}function Kc(t){return!!(t.includes("=")||t.startsWith("@")||t.startsWith("-")||t.indexOf(":")>0&&t[0]>="A"&&t[0]<="Z")}function Qr(t,e,r){let n=e.split("."),i=t;for(let s=0;s<n.length;s++){let o=n[s];if(jc.has(o))throw new Error(`invalid field name: ${o}`);if(s===n.length-1){Object.defineProperty(i,o,{value:r,writable:!0,enumerable:!0,configurable:!0});return}(!Object.hasOwn(i,o)||typeof i[o]!="object"||i[o]===null)&&Object.defineProperty(i,o,{value:{},writable:!0,enumerable:!0,configurable:!0}),i=i[o]}}var zc,jc,Ye=I(()=>{"use strict";g();l();zc={readFile(t){try{return Fc(t)}catch(e){throw new Error(`reading file ${t}: ${e.message}`)}},readStdin(){let t=[],e=Buffer.alloc(65536),r;try{r=Uc("/dev/stdin","r")}catch{throw new Error("reading stdin: cannot open")}try{let n;for(;(n=qc(r,e))>0;)t.push(Buffer.from(e.subarray(0,n)))}catch{}return Bc(r),Buffer.concat(t)}};jc=new Set(["__proto__","constructor","prototype"])});var eo={};jt(eo,{outputResult:()=>Yc});function Yc(t,e){let r=JSON.stringify(t.data),n=t.status>=400;if(e)try{process.stdout.write(Vr(new TextEncoder().encode(r),e)+`
|
|
67
67
|
`)}catch(i){process.stdout.write(r+`
|
|
68
68
|
`),process.stderr.write(`jq error: ${i.message}
|
|
69
69
|
`)}else n&&process.stdout.isTTY||(process.stdout.isTTY?process.stdout.write(JSON.stringify(t.data,null,2)+`
|
|
70
70
|
`):process.stdout.write(r+`
|
|
71
71
|
`));if(n){let i=t.data?.message||t.data?.errorMessage||r.slice(0,200),s=t.data?.hint,o=t.data?.correlationId,a=t.headers?.get("trace-id"),c=[a?`trace ${a}`:"",o?`correlation ${o}`:""].filter(Boolean).join(", ");throw new Error(`${i} (HTTP ${t.status})${c?` [${c}]`:""}${s?`
|
|
72
|
-
Hint: ${s}`:""}`)}}var
|
|
73
|
-
Re-run with --allow-plaintext-secrets to write secrets to ${
|
|
72
|
+
Hint: ${s}`:""}`)}}var ro=I(()=>{"use strict";g();l();Hr()});g();l();g();l();tt();Ze();import{createInterface as dr}from"node:readline/promises";import{readFileSync as xo}from"node:fs";function At(t,e={}){sr(()=>{let r=J();t(r),at(r,{allowPlaintext:e.allowPlaintext})})}function wo(t){let e=[];if(t.keyFile&&e.push("key-file"),(t.keyId||t.keySecret)&&e.push("key-id/--key-secret"),t.status&&e.push("status"),t.remove&&e.push("remove"),e.length>1)throw new Error(`--${e.join(", --")} are mutually exclusive on \`coinbase env\`. Pick one.`)}function ur(t,e){if(!e&&!pn())throw new Error(`OS keychain unavailable; refusing to persist secrets for "${t}".
|
|
73
|
+
Re-run with --allow-plaintext-secrets to write secrets to ${nt()} (file is mode 0600), or install/unlock your OS keychain (macOS Keychain, libsecret on Linux, Windows Credential Manager).`)}async function On(t,e){wo(e);let r=J();if(t.length===0){let _=[...new Set([...Object.keys(r.environments),...Object.keys(X)])].sort();if(_.length===0){process.stderr.write(`No environments configured. Run: coinbase env <name>
|
|
74
74
|
`);return}let u=Math.max(14,..._.map(E=>E.length)),f=45,O=E=>(E.length>f?E.slice(0,f-3)+"...":E).padEnd(f);process.stdout.write(`${"Environment".padEnd(u)} ${"Brokerage API".padEnd(f)} ${"Agent API".padEnd(f)} Key
|
|
75
|
-
`);for(let E of _){let x=r.environments[E]??{},w=Z(x,E),
|
|
76
|
-
`)}return}let n=t[0];if(e.remove){At(_=>{delete _.environments[n],_.env===n&&(_.env="")}),
|
|
77
|
-
`);return}let i=r.environments[n]??{};if(e.status){
|
|
78
|
-
`)),e.brokerageApiUrl&&(i.endpoints={...i.endpoints,brokerageApi:e.brokerageApiUrl}),e.agentApiUrl&&(i.endpoints={...i.endpoints,agentApi:e.agentApiUrl})};if(e.keyFile){
|
|
79
|
-
`);return}if(e.keyId||e.keySecret||e.url||e.brokerageApiUrl||e.agentApiUrl){let _=Yt(i),u=_?.type==="cdp_key"?_.key_id:"",f=_?.type==="cdp_key"?_.key_secret:"";(e.keyId||e.keySecret)&&(
|
|
75
|
+
`);for(let E of _){let x=r.environments[E]??{},w=Z(x,E),N=lt(x,E),F=Yt(x),Y=F?.type==="cdp_key"?F.key_id:"(no key)",R=Y.length>60?Y.slice(0,57)+"...":Y;process.stdout.write(`${E===r.env?"* ":" "}${E.padEnd(u)} ${O(w||"\u2014")} ${O(N||"\u2014")} ${R}
|
|
76
|
+
`)}return}let n=t[0];if(e.remove){At(_=>{delete _.environments[n],_.env===n&&(_.env="")}),ir(n),process.stderr.write(`Removed ${n}.
|
|
77
|
+
`);return}let i=r.environments[n]??{};if(e.status){No(n,i);return}let s=(_,u)=>{i.auth={type:"cdp_key",key_id:_,key_secret:u}},o=()=>{e.url&&(i.url=e.url,ke(e.url)||process.stderr.write(`warning: custom brokerage URL does not match a known endpoint
|
|
78
|
+
`)),e.brokerageApiUrl&&(i.endpoints={...i.endpoints,brokerageApi:e.brokerageApiUrl}),e.agentApiUrl&&(i.endpoints={...i.endpoints,agentApi:e.agentApiUrl})};if(e.keyFile){ur(n,!!e.allowPlaintextSecrets);let _=Go(e.keyFile);s(_.keyId,_.keySecret),o(),At(u=>{u.environments[n]=i,u.env=n},{allowPlaintext:e.allowPlaintextSecrets}),process.stderr.write(`Loaded key from ${e.keyFile}. Switched to ${n}.
|
|
79
|
+
`);return}if(e.keyId||e.keySecret||e.url||e.brokerageApiUrl||e.agentApiUrl){let _=Yt(i),u=_?.type==="cdp_key"?_.key_id:"",f=_?.type==="cdp_key"?_.key_secret:"";(e.keyId||e.keySecret)&&(ur(n,!!e.allowPlaintextSecrets),s(e.keyId??u,e.keySecret??f)),o(),At(O=>{O.environments[n]=i,O.env=n},{allowPlaintext:e.allowPlaintextSecrets}),process.stderr.write(`Saved and switched to ${n}.
|
|
80
80
|
`);return}if(Yt(i)){At(_=>{_.env=n}),process.stderr.write(`Switched to ${n}.
|
|
81
81
|
`);return}if(r.environments[n]){At(_=>{_.env=n}),process.stderr.write(`Switched to ${n} (no credentials yet).
|
|
82
82
|
`),process.stderr.write(` CDP key: coinbase env ${n} --key-file path/to/key.json
|
|
83
|
-
`);return}if(!process.stdout.isTTY)throw new Error(`environment "${n}" needs API keys. Run: coinbase env ${n} --key-id=... --key-secret=...`);
|
|
84
|
-
`)}function
|
|
83
|
+
`);return}if(!process.stdout.isTTY)throw new Error(`environment "${n}" needs API keys. Run: coinbase env ${n} --key-id=... --key-secret=...`);ur(n,!!e.allowPlaintextSecrets);let c="",d="",p=dr({input:process.stdin,output:process.stderr});try{if(!c){let _=await p.question("API Key ID: ");if(!_.trim())throw new Error("API Key ID is required");c=_.trim()}if(!d){p.close();let _=await Ao("API Key Secret: ");if(!_.trim())throw new Error("API Key Secret is required");d=_.trim(),p=dr({input:process.stdin,output:process.stderr})}if(s(c,d),!Z(i,n)){let _=await p.question("Brokerage API URL (optional): ");_.trim()&&(i.endpoints={...i.endpoints,brokerageApi:_.trim()})}if(!lt(i,n)){let _=await p.question("Agent API URL (optional): ");_.trim()&&(i.endpoints={...i.endpoints,agentApi:_.trim()})}}finally{p.close()}At(_=>{_.environments[n]=i,_.env=n},{allowPlaintext:e.allowPlaintextSecrets}),process.stderr.write(`Saved. Switched to ${n}.
|
|
84
|
+
`)}function Ao(t){return process.stderr.write(t),process.stdin.isTTY?new Promise(e=>{let r=process.stdin;r.setRawMode(!0),r.resume(),r.setEncoding("utf8");let n="",i=s=>{s===`
|
|
85
85
|
`||s==="\r"||s===""?(r.setRawMode(!1),r.pause(),r.removeListener("data",i),process.stderr.write(`
|
|
86
|
-
`),e(n)):s==="\x7F"||s==="\b"?n=n.slice(0,-1):s===""?process.exit(1):n+=s};r.on("data",i)}):new Promise(e=>{let r=
|
|
86
|
+
`),e(n)):s==="\x7F"||s==="\b"?n=n.slice(0,-1):s===""?process.exit(1):n+=s};r.on("data",i)}):new Promise(e=>{let r=dr({input:process.stdin});r.once("line",n=>{r.close(),e(n)})})}function Co(t){return t?t.length<=12?"***":t.slice(0,8)+"\u2026"+t.slice(-4):"(none)"}function No(t,e){(!e.auth||e.auth.type!=="cdp_key")&&(process.stderr.write(`Environment "${t}" has no stored credentials.
|
|
87
87
|
`),process.exit(1)),process.stdout.write(`env: ${t}
|
|
88
88
|
`),process.stdout.write(`brokerage_api: ${Z(e,t)||"(unset)"}
|
|
89
89
|
`),process.stdout.write(`agent_api: ${lt(e,t)||"(unset)"}
|
|
90
90
|
`),process.stdout.write(`auth: cdp_key
|
|
91
|
-
`),process.stdout.write(`key_id: ${
|
|
92
|
-
`)}function
|
|
91
|
+
`),process.stdout.write(`key_id: ${Co(e.auth.key_id)}
|
|
92
|
+
`)}function Go(t){let e;try{e=xo(t,"utf-8")}catch{throw new Error(`cannot read key file: ${t}`)}let r;try{r=JSON.parse(e)}catch{throw new Error(`key file is not valid JSON: ${t}`)}let n=r.name??r.id,i=r.privateKey??r.secret;if(!n||!i)throw new Error(`key file must contain name/privateKey (or id/secret): ${t}`);return{keyId:n,keySecret:i}}g();l();Ct();Te();fr();tt();Ce();import{createInterface as Da}from"node:readline";g();l();function Ne(){let t=process.env.COINBASE_TRANSPORT;if(!t||t==="auto")return"auto";if(t==="brokerage")return"brokerage";if(t==="agent")return"agent";throw new Error(`invalid COINBASE_TRANSPORT value "${t}"; expected "auto", "agent", or "brokerage"`)}xe();g();l();tt();mt();function M(t,e=!1){return{content:[{type:"text",text:t}],isError:e}}function ee(t,e){return t===e?`coinbase_${t.replace(/-/g,"_")}`:`coinbase_${t.replace(/-/g,"_")}_${e.replace(/[-\s]/g,"_")}`}function Gi(t){let e=[{name:"coinbase_env",description:"Show the active environment and configured environments.",inputSchema:{type:"object",properties:{}}},{name:"coinbase_set_env",description:"Switch the active environment.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Environment name"}},required:["name"]}},{name:"coinbase_template",description:"Get a full request body example for a command, ready to copy and modify.",inputSchema:{type:"object",properties:{resource:{type:"string",description:'Resource name (e.g. "orders"). Omit for top-level actions like balance, transfer, fees.'},action:{type:"string",description:'Action name (e.g. "create", "balance")'}},required:["action"]}},{name:"coinbase_help",description:"Get detailed help for a command: field descriptions, query parameters, and usage.",inputSchema:{type:"object",properties:{resource:{type:"string",description:'Resource name (e.g. "orders"). Omit for top-level actions like balance, transfer, fees.'},action:{type:"string",description:'Action name (e.g. "create", "balance")'}},required:["action"]}}];for(let r of t)for(let n of r.actions){let i={},s=[];for(let u of n.params){let f={type:u.type,description:u.description};u.enum&&(f.enum=u.enum),u.pattern&&(f.pattern=u.pattern),u.format&&(f.format=u.format),u.example!==void 0&&(f.example=u.example),u.default!==void 0&&(f.default=u.default),i[u.name]=f,u.required&&s.push(u.name)}let o=n.params.filter(u=>u.in==="body").length,a=n.params.filter(u=>u.in==="body"&&u.required).length,c=o>0?a>0?` (${o} fields, ${a} required)`:` (${o} fields)`:"",p=[...new Set(n.params.map(u=>u.oneOf).filter(u=>!!u))].map(u=>` (one of: ${u.split("|").join(", ")})`).join(""),_=n.description||n.summary;e.push({name:ee(r.name,n.name),description:`${n.method} ${n.path}${_?" \u2014 "+_:""}${c}${p}`,inputSchema:{type:"object",properties:i,required:s.length>0?s:void 0}})}return e}function Di(t){if(t.status>=400){let e=t.data?.message??JSON.stringify(t.data).slice(0,200),r=t.data?.correlationId,n=t.headers?.get("trace-id"),i=[n?`trace ${n}`:"",r?`correlation ${r}`:""].filter(Boolean).join(", ");return M(`HTTP ${t.status}: ${e}${i?` [${i}]`:""}`,!0)}if(t.data&&typeof t.data=="object"&&"error"in t.data&&typeof t.data.error=="string"){let e=t.data.message?D.stripGrpcPrefix(t.data.message):t.data.error;return M(`Error: ${e}`,!0)}return M(JSON.stringify(t.data,null,2))}function vr(t){let e=wt(t,""),r=Object.keys(t.environments??{}),n=[`Active: ${e||"(none)"}`,`Configured: ${r.length>0?r.join(", "):"(none)"}`];return e||n.push(`
|
|
93
93
|
Run: coinbase env <name> --key-id=... --key-secret=... to configure.`),M(n.join(`
|
|
94
|
-
`))}function
|
|
95
|
-
`))}function
|
|
94
|
+
`))}function Li(t,e){if(!e)return M("Environment name is required.",!0);let r=Object.keys(t.environments??{});return r.length===0?M("No environments configured. Run: coinbase env <name> --key-id=... --key-secret=... to configure.",!0):t.environments[e]?{cfg:{...t,env:e}}:M(`Unknown environment: "${e}". Available environments: ${r.join(", ")}`,!0)}function Mi(t){return vr(t)}function Na(t,e){let r=t.params??[],n=[];n.push(`${t.summary||t.name}`),n.push(`${t.method} ${t.path}`);let i=t.pathParams.map(a=>`${a}="..."`).join(", ");n.push("",`Usage: ${e}(${i})`);let s=r.filter(a=>a.in==="body");if(s.length>0){n.push("","Fields:");for(let a of s){let c=a.required?" (required)":"",d=a.description?` \u2014 ${a.description}`:"";n.push(` ${a.name} (${a.type})${c}${d}`)}}let o=r.filter(a=>a.in==="query");if(o.length>0){n.push("","Query parameters:");for(let a of o){let c=a.description?` \u2014 ${a.description}`:"";n.push(` ${a.name} (${a.type})${c}`)}}return M(n.join(`
|
|
95
|
+
`))}function Fi(t,e,r,n){if(n&&Object.hasOwn(n,e)&&(!t||t===e))return{act:n[e],toolName:`coinbase_${e}`};if(t){let o=r.find(a=>a.name===t);if(o){let a=o.actions.find(c=>c.name===e);return a?{act:a,toolName:ee(o.name,a.name)}:M(`Unknown action: ${e}. Available for ${t}: ${o.actions.map(c=>c.name).join(", ")}`,!0)}}let i=r.map(o=>o.name),s=n?Object.keys(n):[];return M(`Not found. Resources: ${i.join(", ")}. Top-level actions: ${s.join(", ")}`,!0)}function Ui(t,e,r,n){if(!e)return M("action is required",!0);let i=Fi(t,e,r,n);return"isError"in i?i:Na(i.act,i.toolName)}function Ga(t){let e=(t.params??[]).filter(i=>i.in==="body");if(e.length===0)return M("This action has no request body.");let r=t.template??{},n=[];for(let i of e){let s=i.required?" (required)":"",o=i.description?` \u2014 ${i.description}`:"";n.push(`${i.name} (${i.type})${s}${o}`)}return M(`Template:
|
|
96
96
|
${JSON.stringify(r,null,2)}
|
|
97
97
|
|
|
98
98
|
Fields:
|
|
99
99
|
${n.join(`
|
|
100
|
-
`)}`)}function
|
|
101
|
-
`)}function
|
|
100
|
+
`)}`)}function qi(t,e,r,n){if(!e)return M("action is required",!0);let i=Fi(t,e,r,n);return"isError"in i?i:Ga(i.act)}var La=(()=>{let t={},e=(r,n)=>{let i=t[r];if(i!==void 0&&i!==n)throw new Error(`operationIdForTool collision: tool "${r}" maps to both "${i}" and "${n}"`);t[r]=n};for(let r of Object.values(rt))e(ee(r.name,r.name),r.id);for(let r of et)for(let n of r.actions)e(ee(r.name,n.name),n.id);return t})();function zi(t){process.stdout.write(JSON.stringify({jsonrpc:"2.0",...t})+`
|
|
101
|
+
`)}function re(t,e){zi({id:t,result:e})}function ne(t,e,r){zi({id:t,error:{code:e,message:r}})}function Ma(){return et}async function Fa(t,e){let r=Ma();if(t==="coinbase_env")return vr(J());if(t==="coinbase_set_env"){let n=J(),i=Li(n,e.name);return"isError"in i?i:(at(i.cfg),or(),Mi(i.cfg))}return t==="coinbase_help"?Ui(String(e.resource??""),String(e.action??""),r,rt):t==="coinbase_template"?qi(String(e.resource??""),String(e.action??""),r,rt):Ua(t,e)}async function Ua(t,e){let r=La[t];if(!r||!Pe(r))return M(`Unknown tool: ${t}`,!0);let n=J(),i;try{i=Jt(n,"")}catch(a){return M(`Environment error: ${a.message}
|
|
102
102
|
|
|
103
|
-
Run: coinbase env <name> --key-id=... --key-secret=...`,!0)}let{name:s,env:o}=i;try{let a=await Qt(s,o),c={envName:s,env:o,baseURL:Z(o,s),doRequest:p=>
|
|
104
|
-
`),n.id!=null&&
|
|
105
|
-
`)}g();l();tt();function
|
|
106
|
-
`);return}throw new Error("usage: coinbase history [clear [env.action]]")}function
|
|
103
|
+
Run: coinbase env <name> --key-id=... --key-secret=...`,!0)}let{name:s,env:o}=i;try{let a=await Qt(s,o),c={envName:s,env:o,baseURL:Z(o,s),doRequest:p=>Ae({...p,...a}),transport:Ne()},d=await Gt(r,e,c);return Di(d)}catch(a){return M(`Request failed: ${a.message}`,!0)}}var qa={name:"coinbase",version:ct},Ba={tools:{}},kr=null;function Bi(){if(!kr){let t=[...et];for(let[e,r]of Object.entries(rt))t.push({name:e,actions:[r]});kr=Gi(t)}return kr}async function za(t){let{id:e,method:r,params:n}=t;switch(r){case"initialize":re(e,{protocolVersion:"2024-11-05",serverInfo:qa,capabilities:Ba});break;case"notifications/initialized":break;case"tools/list":re(e,{tools:Bi()});break;case"tools/call":{let{name:i,arguments:s}=n??{};if(!i){ne(e,-32602,"Missing tool name");return}if(!Bi().find(a=>a.name===i)){ne(e,-32602,`Unknown tool: ${i}`);return}try{let a=await Fa(i,s??{});re(e,a)}catch(a){re(e,M(`Internal error: ${a.message}`,!0))}break}case"ping":re(e,{});break;default:e!=null&&ne(e,-32601,`Method not found: ${r}`);break}}function Wi(){let t=Da({input:process.stdin,terminal:!1}),e=new Set;t.on("line",r=>{if(r.trim())try{let n=JSON.parse(r),i=za(n).catch(s=>{process.stderr.write(`MCP error: ${s.message}
|
|
104
|
+
`),n.id!=null&&ne(n.id,-32603,s.message)}).finally(()=>e.delete(i));e.add(i)}catch{ne(null,-32700,"Parse error")}}),t.on("close",async()=>{await Promise.all(e),process.exit(0)}),process.stderr.write(`coinbase MCP server v${ct} ready
|
|
105
|
+
`)}g();l();tt();function $i(t){let e=J();if(t.length===0)return Wa(e);if(t[0]==="clear"){let r=t[1],n;if(r&&r.includes(".")){let i=r.indexOf(".");n=Xt(e,r.slice(0,i),r.slice(i+1))}else r?n=Xt(e,r):n=Xt(e);at(e),process.stderr.write(`Cleared ${n} history ${n===1?"entry":"entries"}.
|
|
106
|
+
`);return}throw new Error("usage: coinbase history [clear [env.action]]")}function Wa(t){let e=[];for(let[i,s]of Object.entries(t.history))for(let[o,a]of Object.entries(s))e.push({env:i,action:o,lastUsed:a.last_used,fields:Object.keys(a.values)});if(e.length===0){process.stderr.write(`No saved history.
|
|
107
107
|
`);return}e.sort((i,s)=>s.lastUsed.localeCompare(i.lastUsed));let r=Math.max(...e.map(i=>i.env.length))+2,n=Math.max(...e.map(i=>i.action.length))+2;for(let i of e){let s=i.lastUsed.slice(0,10);process.stdout.write(`${i.env.padEnd(r)}${i.action.padEnd(n)}${s} ${i.fields.join(", ")}
|
|
108
|
-
`)}}g();l();tt();import{readFileSync as
|
|
109
|
-
`,{mode:384})}function
|
|
108
|
+
`)}}g();l();tt();import{readFileSync as Yi,writeFileSync as $a,mkdirSync as Qi,readdirSync as Ji,existsSync as Ot,cpSync as Va,rmSync as Ha}from"node:fs";import Vi,{join as _t,resolve as Hi}from"node:path";import{fileURLToPath as ja}from"node:url";import{homedir as ji}from"node:os";import{createInterface as Ki}from"node:readline";function Rr(){try{return JSON.parse(Yi(nt(),"utf8"))}catch{return{}}}function Or(t){let e=gt();Qi(e,{recursive:!0,mode:448}),$a(nt(),JSON.stringify(t,null,2)+`
|
|
109
|
+
`,{mode:384})}function Xi(){let t=Vi.dirname(ja(import.meta.url));return Vi.join(t,"..","skills")}function Ka(t){let e=t.match(/^---\n([\s\S]*?)\n---/);if(!e)return{name:"",description:""};let r=e[1],n=r.match(/^name:\s*(.+)$/m),i=r.match(/^description:\s*(.+)$/m);return{name:(n?.[1]??"").trim(),description:(i?.[1]??"").trim()}}function Zi(t){let e=t??Xi();if(!Ot(e))return[];let r=[];for(let n of Ji(e,{withFileTypes:!0})){if(!n.isDirectory())continue;let i=_t(e,n.name,"SKILL.md");if(!Ot(i))continue;let s=Yi(i,"utf8"),o=Ka(s);r.push({name:o.name||n.name,description:o.description,dir:_t(e,n.name)})}return r.sort((n,i)=>n.name.localeCompare(i.name))}function Ya(t,e){if(!Ot(t))return 0;Qi(e,{recursive:!0});let r=0;for(let n of Ji(t,{withFileTypes:!0})){if(!n.isDirectory())continue;let i=_t(t,n.name,"SKILL.md");if(!Ot(i))continue;let s=_t(e,n.name);Va(_t(t,n.name),s,{recursive:!0,force:!0}),r++}return r}async function Qa(){let t=process.platform==="win32"?_t(process.env.USERPROFILE??ji(),".claude","skills"):_t(ji(),".claude","skills");process.stderr.write(`Where should skills be installed?
|
|
110
110
|
`),process.stderr.write(`Tip: Not sure where your agent looks for skills? Ask your agent.
|
|
111
111
|
|
|
112
112
|
`),process.stderr.write(` 1) ${t} User \u2014 available across all projects (Recommended)
|
|
113
113
|
`),process.stderr.write(` 2) Other Specify a custom path
|
|
114
114
|
|
|
115
|
-
`);let e=
|
|
116
|
-
`),t)}return
|
|
115
|
+
`);let e=Ki({input:process.stdin,output:process.stderr}),r=await new Promise(n=>{e.question("? Skills directory [1]: ",i=>{e.close(),n(i.trim())})});if(!r||r==="1")return t;if(r==="2"){let n=Ki({input:process.stdin,output:process.stderr}),i=await new Promise(s=>{n.question("? Path: ",o=>{n.close(),s(o.trim())})});return i?Hi(i):(process.stderr.write(`No path provided, using default.
|
|
116
|
+
`),t)}return Hi(r)}async function Ja(t){let e=Rr(),r=t||e.settings?.skillsDir,n=!1;r||(process.stdin.isTTY||(process.stderr.write(`error: no skills directory configured.
|
|
117
117
|
Run: coinbase skills add --dir <path>
|
|
118
|
-
`),process.exit(1)),r=await
|
|
118
|
+
`),process.exit(1)),r=await Qa(),n=!0),(!e.settings?.skillsDir||t&&e.settings.skillsDir!==r)&&(e.settings||(e.settings={}),e.settings.skillsDir=r,Or(e));let i=Xi(),s=Ya(i,r);process.stderr.write(`Installed ${s} skills to ${r}.
|
|
119
119
|
`),n&&process.stderr.write(`Skills will auto-update on future installs.
|
|
120
|
-
`)}function
|
|
120
|
+
`)}function Xa(){let e=Rr().settings?.skillsDir,r=Zi();if(r.length===0){process.stderr.write(`No bundled skills found.
|
|
121
121
|
`);return}let n=Math.max(...r.map(i=>i.name.length),4);process.stderr.write(`${"Name".padEnd(n+2)}${"Installed".padEnd(12)}Description
|
|
122
122
|
`),process.stderr.write(`${"\u2500".repeat(n+2)}${"\u2500".repeat(12)}${"\u2500".repeat(40)}
|
|
123
123
|
`);for(let i of r){let o=e&&Ot(_t(e,i.name,"SKILL.md"))?"yes":"no";process.stderr.write(`${i.name.padEnd(n+2)}${o.padEnd(12)}${i.description}
|
|
124
124
|
`)}process.stderr.write(`
|
|
125
125
|
${r.length} skills available.`),e?process.stderr.write(` Installed to: ${e}`):process.stderr.write(" Run: coinbase skills add"),process.stderr.write(`
|
|
126
|
-
`)}function
|
|
126
|
+
`)}function Za(){let t=Rr(),e=t.settings?.skillsDir;if(!e){process.stderr.write(`No skills directory configured. Nothing to remove.
|
|
127
127
|
`);return}if(!Ot(e)){process.stderr.write(`Skills directory not found: ${e}
|
|
128
|
-
`),t.settings&&delete t.settings.skillsDir,
|
|
129
|
-
`);return}let r=
|
|
128
|
+
`),t.settings&&delete t.settings.skillsDir,Or(t),process.stderr.write(`Cleared skillsDir from config.
|
|
129
|
+
`);return}let r=Zi(),n=0;for(let i of r){let s=_t(e,i.name);Ot(s)&&(Ha(s,{recursive:!0,force:!0}),n++)}t.settings&&delete t.settings.skillsDir,Or(t),process.stderr.write(`Removed ${n} skills from ${e}.
|
|
130
130
|
`),process.stderr.write(`Cleared skillsDir from config.
|
|
131
|
-
`)}async function
|
|
131
|
+
`)}async function ts(t){let e=t[0];if(!e||e==="-h"||e==="--help"){process.stderr.write(`Manage CDP agent skills
|
|
132
132
|
|
|
133
133
|
Usage:
|
|
134
134
|
coinbase skills add Install/update skills to your skills directory
|
|
@@ -136,29 +136,29 @@ Usage:
|
|
|
136
136
|
coinbase skills list List available skills from this package
|
|
137
137
|
coinbase skills remove Remove installed skills and clear config
|
|
138
138
|
|
|
139
|
-
`);return}let r,n=t.slice(1);for(let i=0;i<n.length;i++)if(n[i]==="--dir"&&n[i+1]){r=n[++i];break}else if(n[i].startsWith("--dir=")){r=n[i].slice(6);break}switch(e){case"add":await
|
|
139
|
+
`);return}let r,n=t.slice(1);for(let i=0;i<n.length;i++)if(n[i]==="--dir"&&n[i+1]){r=n[++i];break}else if(n[i].startsWith("--dir=")){r=n[i].slice(6);break}switch(e){case"add":await Ja(r);break;case"list":Xa();break;case"remove":Za();break;default:process.stderr.write(`error: unknown skills subcommand: ${e}
|
|
140
140
|
Run: coinbase skills --help
|
|
141
|
-
`),process.exit(1)}}g();l();Ct();g();l();
|
|
141
|
+
`),process.exit(1)}}g();l();Ct();g();l();Ge();function ec(t,e,r){return r?`\x1B]8;;${e}\x07\x1B[4m${t}\x1B[24m\x1B]8;;\x07`:`${t} (${e})`}function rs(t,e=es){return t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(r,n,i)=>ec(n,i,e))}function Pr(t){return t.replace(/\*\*(.+?)\*\*/g,"$1").replace(/__(.+?)__/g,"$1").replace(/\*(.+?)\*/g,"$1").replace(/_(.+?)_/g,"$1").replace(/\[([^\]]+)\]\([^)]+\)/g,"$1").replace(/^#{1,6}\s+/gm,"")}function ns(t,e){let r=e??process.stdout.columns??100;return t.replace(/\r\n/g,`
|
|
142
142
|
`).trim().split(`
|
|
143
|
-
`).flatMap(n=>{n=
|
|
143
|
+
`).flatMap(n=>{n=Pr(n).replace(/^\s*\*\s+/," - ").replace(/^\s*(\d+)\.\s+/," $1. ");let i=[];for(;n.length>r;){let s=n.lastIndexOf(" ",r);s<=0&&(s=r),i.push(n.slice(0,s)),n=n.slice(s+1)}return i.push(n),i}).join(`
|
|
144
144
|
`)+`
|
|
145
|
-
`}g();l();
|
|
145
|
+
`}g();l();Ge();function De(t,e,r,n){let i=n??e.length,s=Math.max(20,(process.stdout.columns||80)-i),o=r.split(" "),a="",c=!0;for(let d of o){let p=ft(d),_=ft(a),u=d.includes("\x1B]8;;");(_+p+1>s||u&&_>0&&_+p+1>s*.6)&&a.length>0&&(t.write((c?e:" ".repeat(i))+a.trimEnd()+`
|
|
146
146
|
`),a="",c=!1),a+=(a?" ":"")+d}a&&t.write((c?e:" ".repeat(i))+a.trimEnd()+`
|
|
147
|
-
`)}
|
|
148
|
-
`),i&&
|
|
147
|
+
`)}wr();se();_e();function Kr(){return et}function Js(t){return Rn.has(t)}function Xs(t,e,r){for(let n of e.fields){let i=e.nested?.[n];t.write(`${r}${n}
|
|
148
|
+
`),i&&Xs(t,i,r+" ")}}function Yr(t,e){let r=process.stderr,n=st(e.id),i=n?ht(n):null;r.write(`${e.summary||e.name}
|
|
149
149
|
`),e.description&&r.write(`
|
|
150
|
-
`+
|
|
150
|
+
`+ns(e.description));let s=t===e.name?`coinbase ${e.name}`:`coinbase ${t} ${e.name}`;for(let _ of e.pathParams)s+=` <${_}>`;r.write(`
|
|
151
151
|
Usage:
|
|
152
152
|
${s} [fields...]
|
|
153
153
|
`);let o=e.params??[],a=o.filter(_=>_.in==="path");if(a.length>0){r.write(`
|
|
154
154
|
Arguments:
|
|
155
|
-
`);let _=Math.max(...a.map(u=>u.name.length));for(let u of a){let f=` <${u.name}>${" ".repeat(Math.max(1,_-u.name.length+2))}${u.type}${u.required?" required":""} `,O=/[.!?]$/.test(u.description)?u.description:`${u.description}.`,E=i==="watchlist"?`${O} With --watch, accepts multiple comma-separated pairs (e.g. BTC-USD,ETH-USD).`:u.description;
|
|
155
|
+
`);let _=Math.max(...a.map(u=>u.name.length));for(let u of a){let f=` <${u.name}>${" ".repeat(Math.max(1,_-u.name.length+2))}${u.type}${u.required?" required":""} `,O=/[.!?]$/.test(u.description)?u.description:`${u.description}.`,E=i==="watchlist"?`${O} With --watch, accepts multiple comma-separated pairs (e.g. BTC-USD,ETH-USD).`:u.description;De(r,f,E)}}let c=o.filter(_=>_.in==="body");if(c.length>0){r.write(`
|
|
156
156
|
Fields:
|
|
157
|
-
`);let _=Math.max(...c.map(u=>u.name.length));for(let u of c){let f=u.required?"required":"",O=" ".repeat(Math.max(1,_-u.name.length+2)),E=" ".repeat(Math.max(1,8-u.type.length)),x=f?" ":" ",w=u.type==="array"||u.type==="object"?" (use :=json)":"",
|
|
157
|
+
`);let _=Math.max(...c.map(u=>u.name.length));for(let u of c){let f=u.required?"required":"",O=" ".repeat(Math.max(1,_-u.name.length+2)),E=" ".repeat(Math.max(1,8-u.type.length)),x=f?" ":" ",w=u.type==="array"||u.type==="object"?" (use :=json)":"",N=rs(Pr(u.description)),F=` ${u.name}${O}${u.type}${E}${f}${x}`;De(r,F,N+w)}}let d=o.filter(_=>_.in==="query");if(d.length>0){r.write(`
|
|
158
158
|
Query params (use == syntax):
|
|
159
|
-
`);let _=Math.max(...d.map(u=>u.name.length));for(let u of d){let f=u.description;u.enum?.length&&(f+=(f?" ":"")+`[${u.enum.join(", ")}]`);let O=` ${u.name}${" ".repeat(Math.max(1,_-u.name.length+2))}${u.type} `;
|
|
159
|
+
`);let _=Math.max(...d.map(u=>u.name.length));for(let u of d){let f=u.description;u.enum?.length&&(f+=(f?" ":"")+`[${u.enum.join(", ")}]`);let O=` ${u.name}${" ".repeat(Math.max(1,_-u.name.length+2))}${u.type} `;De(r,O,f)}}e.responseFields&&(r.write(`
|
|
160
160
|
Response:
|
|
161
|
-
`),
|
|
161
|
+
`),Xs(r,e.responseFields," "));let p=c.length>0;if(r.write(`
|
|
162
162
|
Flags:
|
|
163
163
|
`),p&&r.write(` --template Show request body template from spec
|
|
164
164
|
`),r.write(` --dry-run Preview request without sending
|
|
@@ -167,17 +167,17 @@ Flags:
|
|
|
167
167
|
`),e.streamable&&r.write(` --paginate Auto-paginate using nextPageToken
|
|
168
168
|
`),i!==null&&(r.write(` --watch Live stream via WebSocket
|
|
169
169
|
`),e.watchFields&&(r.write(`
|
|
170
|
-
`+
|
|
170
|
+
`+ss(e.watchFields)+`
|
|
171
171
|
`),r.write(` --until-timeout <s> Exit 124 if predicate not matched within N seconds
|
|
172
172
|
`))),p||d.length>0){r.write(`
|
|
173
173
|
Example:
|
|
174
174
|
`+s);for(let _ of c)_.example!==void 0&&r.write(` ${_.name}=${_.example}`);for(let _ of d)_.example!==void 0&&r.write(` ${_.name}==${_.example}`);r.write(`
|
|
175
|
-
`)}}function
|
|
175
|
+
`)}}function Zs(t){let e=et.find(n=>n.name===t);e||(process.stderr.write(`error: unknown resource: ${t}
|
|
176
176
|
Run: coinbase --help
|
|
177
177
|
`),process.exit(1)),process.stderr.write(`Manage ${e.name}
|
|
178
178
|
|
|
179
179
|
Available actions:
|
|
180
|
-
`);let r=e.actions.some(n=>{let i=
|
|
180
|
+
`);let r=e.actions.some(n=>{let i=st(n.id);return i&&ht(i)!==null});for(let n of e.actions){let i=st(n.id),o=(i?ht(i):null)!==null?" [--watch]":"",a=n.pathParams.map(c=>` <${c}>`).join("");process.stderr.write(` coinbase ${e.name} ${n.name}${a}${o} ${n.summary}
|
|
181
181
|
`)}process.stderr.write(`
|
|
182
182
|
Flags:
|
|
183
183
|
--template Show request body template from spec
|
|
@@ -185,41 +185,41 @@ Flags:
|
|
|
185
185
|
--edit Open request body in $EDITOR
|
|
186
186
|
--jq <expr> jq filter expression for response
|
|
187
187
|
`),r&&process.stderr.write(` --watch Live stream watchable actions via WebSocket (add --until <predicate> to exit on a condition)
|
|
188
|
-
`)}
|
|
188
|
+
`)}se();_e();g();l();Te();g();l();var to=t=>t?.has_next===!1?null:t?.cursor||null;tt();Ce();se();function Qc(t,e,r,n){for(let i of e){let s=r[i];if(typeof s=="string"&&s.includes(",")){let o=t.replace(/_/g," ");return`'${s}' looks like multiple values, but \`coinbase ${o}\` takes a single ${i}.`+(n?`
|
|
189
189
|
To stream several live, add --watch:
|
|
190
|
-
coinbase ${o} ${s} --watch`:"")}}return null}function
|
|
191
|
-
`);return}let i=[],s=[],{isFieldArg:o}=await Promise.resolve().then(()=>(
|
|
190
|
+
coinbase ${o} ${s} --watch`:"")}}return null}function no(t){return t.history!=="disabled"}async function Jr(t,e,r,n){if(r.flags.template){let v=e.template??{};process.stdout.write(JSON.stringify(v,null,2)+`
|
|
191
|
+
`);return}let i=[],s=[],{isFieldArg:o}=await Promise.resolve().then(()=>(Ye(),Ke));for(let v of r.args)i.length<e.pathParams.length&&!o(v)?i.push(v):s.push(v);if(i.length<e.pathParams.length){let v=e.pathParams.slice(i.length);throw new Error(`Missing argument(s): ${v.map(T=>`<${T}>`).join(" ")}
|
|
192
192
|
|
|
193
|
-
Usage: coinbase ${t.replace(/_/g," ")} ${e.pathParams.map(T=>`<${T}>`).join(" ")} [fields...]`)}let{parseFields:a}=await Promise.resolve().then(()=>(
|
|
194
|
-
`),{...p}):{...c.body},x={};for(let[
|
|
195
|
-
`),r.flags.edit=!0;else{let
|
|
193
|
+
Usage: coinbase ${t.replace(/_/g," ")} ${e.pathParams.map(T=>`<${T}>`).join(" ")} [fields...]`)}let{parseFields:a}=await Promise.resolve().then(()=>(Ye(),Ke)),c=a(s),d=!1,p={},_=J(),u=wt(_,n);if(no(e)&&u&&Oe(_)){let v=_r(_,u,t);if(v){let{setNested:T}=await Promise.resolve().then(()=>(Ye(),Ke));for(let[k,L]of Object.entries(v.values))try{T(p,k,JSON.parse(L))}catch{T(p,k,L)}d=!0}}let f=e.params??[];for(let v of Object.keys(c.body)){let T=f.find(k=>k.name===v);if(T?.oneOf)for(let k of f)k.oneOf===T.oneOf&&k.name!==v&&delete p[k.name]}let E=Object.keys(c.body).length>0?{...p,...c.body}:d?(process.stderr.write(`Using saved values from last ${t.replace(/_/g," ")} call. Pass fields to override.
|
|
194
|
+
`),{...p}):{...c.body},x={};for(let[v,T]of c.query.entries())x[v]=T;let w={};for(let v=0;v<i.length;v++)w[e.pathParams[v]]=i[v];if(!r.flags.watch&&!r.flags.until){let T=e.pathParams.some(k=>typeof w[k]=="string"&&w[k].includes(","))?st(t):null;if(T){let{surfaceForChannel:k}=await Promise.resolve().then(()=>(_e(),jr)),L=Qc(t,e.pathParams,w,k(T)==="watchlist");if(L)throw new Error(L)}}let N=f.filter(v=>v.in==="body"&&v.required&&v.type!=="object"&&v.type!=="array"),F=N.map(v=>v.name);if(F.length>0&&Object.keys(E).length===0&&!r.flags.edit&&!c.rawBody)if(process.stdin.isTTY)if(N.length<=3){let{createInterface:v}=await import("node:readline"),T=v({input:process.stdin,output:process.stderr});for(let k of N){let L=k.enum?` [${k.enum.join(", ")}]`:"",U=k.example?` (e.g. ${k.example})`:"",Et=await new Promise(m=>{T.question(`${k.name}${L}${U}: `,m)});Et&&(E[k.name]=Et)}T.close()}else process.stderr.write(`This action requires ${F.length} fields. Opening editor.
|
|
195
|
+
`),r.flags.edit=!0;else{let v=F.join(", ");throw new Error(`Missing required field(s): ${v}
|
|
196
196
|
|
|
197
197
|
Provide fields inline:
|
|
198
198
|
coinbase ${t.replace(/_/g," ")} ${F.map(T=>`${T}=<value>`).join(" ")}
|
|
199
199
|
|
|
200
200
|
Or use --template to see the full body:
|
|
201
201
|
coinbase ${t.replace(/_/g," ")} --template
|
|
202
|
-
`)}if(r.flags.edit){let T={...e.template??{},...E},
|
|
203
|
-
`);let
|
|
204
|
-
`);return}let Y=
|
|
205
|
-
`);break}}while(!0)}function
|
|
202
|
+
`)}if(r.flags.edit){let T={...e.template??{},...E},k=await Zc(JSON.stringify(T,null,2));for(let L of Object.keys(E))delete E[L];Object.assign(E,k)}if(r.flags["dry-run"]){process.stderr.write(`would execute ${t}
|
|
203
|
+
`);let v={...w,...E,...Object.keys(x).length>0?{_query:x}:{}};process.stdout.write(JSON.stringify(v,null,2)+`
|
|
204
|
+
`);return}let Y=Ne(),{name:R,env:P}=Jt(_,n),H=await Qt(R,P),V={envName:R,env:P,baseURL:Z(P,R),doRequest:v=>Ae({...v,...H}),transport:r.flags.watch||r.flags.until?"brokerage":Y};if(r.flags.watch||r.flags.until){let{startWatch:v}=await Promise.resolve().then(()=>(_e(),jr)),T=i.length>0?i.flatMap(U=>U.split(",")).filter(Boolean):[],k=r.flags.depth?Number(r.flags.depth):void 0,L=r.flags["until-timeout"]?Number(r.flags["until-timeout"]):void 0;if(k!==void 0&&(!Number.isFinite(k)||k<1))throw new Error(`Invalid --depth value: ${r.flags.depth}`);if(L!==void 0&&(!Number.isFinite(L)||L<1))throw new Error(`Invalid --until-timeout value: ${r.flags["until-timeout"]}`);await v(t,T,V,{jq:r.flags.jq,depth:k,until:r.flags.until,untilTimeout:L,query:Object.keys(x).length>0?x:void 0});return}let Q={body:E,query:{...x},path:w,headers:c.headers,rawBody:c.rawBody??void 0},{outputResult:Ht}=await Promise.resolve().then(()=>(ro(),eo)),de=0;do{let v=await Gt(t,Q,V);if(Ht(v,r.flags.jq),no(e)&&v.status<400&&Object.keys(E).length>0)try{if(u&&Oe(_)){let k={};(function L(U,Et){for(let[m,h]of Object.entries(Et)){let A=U?`${U}.${m}`:m;typeof h=="object"&&h&&!Array.isArray(h)?L(A,h):k[A]=JSON.stringify(h)}})("",E),cr(_,u,t,k),at(_)}}catch{}if(!r.flags.paginate)break;let T=to(v.data);if(!T||T===Q.query.cursor)break;if(Q.query.cursor=T,++de>=100){process.stderr.write(`Pagination limit reached (100 pages)
|
|
205
|
+
`);break}}while(!0)}function Jc(){if(process.platform!=="win32")return"vi";try{let{execSync:t}=_o("node:child_process");return t("where code",{stdio:"pipe"}),"code --wait"}catch{}return"notepad"}function Xc(t){return t.split(`
|
|
206
206
|
`).filter(e=>!e.trimStart().startsWith("//")).join(`
|
|
207
|
-
`)}async function
|
|
207
|
+
`)}async function Zc(t){let{writeFileSync:e,readFileSync:r,unlinkSync:n,mkdtempSync:i}=await import("node:fs"),{tmpdir:s}=await import("node:os"),{join:o}=await import("node:path"),{execFileSync:a}=await import("node:child_process"),{scrubbedEnv:c}=await Promise.resolve().then(()=>(tt(),kn));if(!process.stdin.isTTY)throw new Error("--edit requires an interactive terminal. Use --template to get the request body, then pass fields as arguments.");let d=process.env.VISUAL??process.env.EDITOR??Jc();(d.trim()==="code"||d.trim().endsWith("/code"))&&(d+=" --wait");let p=o(i(o(s(),"coinbase-")),"request.json");e(p,t);try{let[_,...u]=d.split(/\s+/);a(_,[...u,p],{stdio:"inherit",env:c()});let f=Xc(r(p,"utf8"));return JSON.parse(f)}catch(_){throw new Error(_.message?.includes("Unexpected")?`Edited file is not valid JSON: ${_.message}`:`Editor: ${_.message}`)}finally{try{n(p)}catch{}}}Ct();g();l();var ue=class extends Error{constructor(e){super(e),this.name="HelpExit"}};function io(t){let e={children:new Map};for(let r of t){let n=e;for(let i of r.name.split(" "))n.children.has(i)||n.children.set(i,{children:new Map}),n=n.children.get(i);n.action=r}return e}function so(t,e,r){let n=t,i,s=0,o=[],a=[];for(let _=0;_<e.length;_++){let u=e[_],f=n.children.get(u);if(f){a.push(u),o=[...n.children.keys()],n=f,n.action&&(i=n.action,s=a.length);continue}if(u.includes("=")){let O=u.split("=")[0],E=n.children.get(O);if(E?.action){let x=E.action.pathParams.map(N=>` <${N}>`).join(""),w=a.length>0?`coinbase ${r} ${a.join(" ")}`:`coinbase ${r}`;throw new Error(`Did you mean: ${w} ${E.action.name.split(" ").pop()}${x}`)}}break}if(i)return{action:i,remaining:e.slice(s),siblingNames:o};let c=e[a.length],d=a.length>0?`coinbase ${r} ${a.join(" ")}`:`coinbase ${r}`,p=t_(n,r);throw c&&c!=="--help"&&c!=="-h"?new Error(`unknown subcommand "${c}" for ${d}
|
|
208
208
|
|
|
209
209
|
Available actions:
|
|
210
|
-
${p}`):new
|
|
210
|
+
${p}`):new ue(`${d}
|
|
211
211
|
|
|
212
212
|
Available actions:
|
|
213
|
-
${p}`)}function
|
|
214
|
-
`)}
|
|
215
|
-
`),process.exit(1));function
|
|
213
|
+
${p}`)}function t_(t,e){let r=[];function n(i){if(i.action){let s=i.action.pathParams.map(o=>` <${o}>`).join("");r.push(` coinbase ${e} ${i.action.name}${s}`)}for(let s of i.children.values())n(s)}return n(t),r.join(`
|
|
214
|
+
`)}xe();le();g();l();function Vt(t,e){let r={},n=[],i=!1,s=new Map;for(let[o,a,c]of e)s.set("--"+o,[o,c]),a&&s.set("-"+a,[o,c]);for(let o=0;o<t.length;o++){let a=t[o];if(a==="-h"||a==="--help"){i=!0;continue}let c=a.indexOf("=");if(c>0&&a.startsWith("--")){let p=s.get(a.slice(0,c));if(p){r[p[0]]=a.slice(c+1);continue}}let d=s.get(a);if(d){r[d[0]]=d[1]?t[++o]??"":!0;continue}if(a.length>2&&a[0]==="-"&&a[1]!=="-"){let p=s.get(a.slice(0,2));if(p?.[1]){r[p[0]]=a.slice(2);continue}}n.push(a)}return{flags:r,args:n,help:i}}process.stdout.on("error",t=>{throw t.code==="EPIPE"&&process.exit(0),t});process.stderr.on("error",t=>{throw t.code==="EPIPE"&&process.exit(0),t});var[e_]=process.versions.node.split(".").map(Number);e_<22&&(process.stderr.write(`coinbase requires Node.js ${22}+. You have: ${process.versions.node}
|
|
215
|
+
`),process.exit(1));function r_(){return`Coinbase CLI
|
|
216
216
|
|
|
217
217
|
Usage:
|
|
218
218
|
coinbase <resource> <action> [fields...]
|
|
219
219
|
coinbase <action> [fields...]
|
|
220
220
|
|
|
221
221
|
Resources:
|
|
222
|
-
${
|
|
222
|
+
${Kr().map(r=>` ${r.name.padEnd(20)}${r.actions.map(n=>{let i=st(n.id);return i&&ht(i)!==null?`${n.name} [--watch]`:n.name}).join(", ")}`).join(`
|
|
223
223
|
`)}
|
|
224
224
|
|
|
225
225
|
Actions:
|
|
@@ -239,8 +239,8 @@ Flags:
|
|
|
239
239
|
-e, --env <name> Environment override
|
|
240
240
|
-V, --version Show version
|
|
241
241
|
-h, --help Show help
|
|
242
|
-
`}async function
|
|
243
|
-
`);return}if(
|
|
242
|
+
`}async function n_(){let t=process.argv.slice(2),e="",r=[];for(let s=0;s<t.length;s++){let o=t[s];o==="-e"||o==="--env"?e=t[++s]??"":o.startsWith("--env=")?e=o.slice(6):o.startsWith("-e")&&o.length>2?e=o.slice(2):r.push(o)}if(r[0]==="--version"||r[0]==="-V"){process.stdout.write(`coinbase ${ct}
|
|
243
|
+
`);return}if(Xr=wi(),r.length===0||r[0]==="-h"||r[0]==="--help"||r[0]==="help"){process.stderr.write(r_());return}let[n,...i]=r;if(n==="env"){let s=Vt(i,[["key-id",null,!0],["key-secret",null,!0],["key-file","k",!0],["status",null,!1],["url",null,!0],["brokerage-api-url",null,!0],["agent-api-url",null,!0],["remove",null,!1],["allow-plaintext-secrets",null,!1]]);if(s.help){process.stderr.write(`Manage environments and credentials
|
|
244
244
|
|
|
245
245
|
Usage:
|
|
246
246
|
coinbase env List all environments
|
|
@@ -261,14 +261,14 @@ Flags:
|
|
|
261
261
|
--agent-api-url <url> First-party Agent API URL (includes /api)
|
|
262
262
|
--remove Remove an environment
|
|
263
263
|
--allow-plaintext-secrets Persist secrets to ~/.config/coinbase/config.json (mode 0600) when no OS keychain is available. Default: refuse and error.
|
|
264
|
-
`);return}await
|
|
264
|
+
`);return}await On(s.args,{keyId:s.flags["key-id"],keySecret:s.flags["key-secret"],keyFile:s.flags["key-file"],status:!!s.flags.status,url:s.flags.url,brokerageApiUrl:s.flags["brokerage-api-url"],agentApiUrl:s.flags["agent-api-url"],remove:!!s.flags.remove,allowPlaintextSecrets:!!s.flags["allow-plaintext-secrets"],envFlag:e})}else if(n==="history"){let s=Vt(i,[]);if(s.help){process.stderr.write(`View or clear saved request history
|
|
265
265
|
|
|
266
266
|
Usage:
|
|
267
267
|
coinbase history Show all saved history
|
|
268
268
|
coinbase history clear Clear all history
|
|
269
269
|
coinbase history clear <env> Clear history for an environment
|
|
270
270
|
coinbase history clear <env>.<action> Clear a specific entry
|
|
271
|
-
`);return}
|
|
271
|
+
`);return}$i(s.args)}else if(n==="skills")await ts(i);else if(n==="mcp"){if(Vt(i,[]).help){process.stderr.write(`MCP server for AI agent integration
|
|
272
272
|
|
|
273
273
|
Usage:
|
|
274
274
|
coinbase mcp Start MCP server over stdio
|
|
@@ -276,9 +276,9 @@ Usage:
|
|
|
276
276
|
The MCP server implements the Model Context Protocol (JSON-RPC over
|
|
277
277
|
stdin/stdout) and exposes brokerage and x402 API resources as tools. It is
|
|
278
278
|
typically invoked automatically by AI agents, not run directly.
|
|
279
|
-
`);return}
|
|
280
|
-
`),process.exit(1));let o=Vt(i,[["template",null,!1],["dry-run",null,!1],["edit",null,!1],["jq",null,!0],["paginate",null,!1],["watch",null,!1],["depth",null,!0],["until",null,!0],["until-timeout",null,!0]]);if(o.help){
|
|
279
|
+
`);return}Wi()}else if(Js(n)){let s=rt[n];s||(process.stderr.write(`error: "${n}" is not available
|
|
280
|
+
`),process.exit(1));let o=Vt(i,[["template",null,!1],["dry-run",null,!1],["edit",null,!1],["jq",null,!0],["paginate",null,!1],["watch",null,!1],["depth",null,!0],["until",null,!0],["until-timeout",null,!0]]);if(o.help){Yr(n,s);return}await Jr(n,s,o,e)}else{let s=Kr().find(p=>p.name===n);if(s||(process.stderr.write(`error: unknown command "${n}"
|
|
281
281
|
Run: coinbase --help
|
|
282
|
-
`),process.exit(1)),i.length===0||i[0]==="-h"||i[0]==="--help"){
|
|
282
|
+
`),process.exit(1)),i.length===0||i[0]==="-h"||i[0]==="--help"){Zs(n);return}let o=io(s.actions),a=so(o,i,n),c=Vt(a.remaining,[["template",null,!1],["dry-run",null,!1],["edit",null,!1],["jq",null,!0],["paginate",null,!1],["watch",null,!1],["depth",null,!0],["until",null,!0],["until-timeout",null,!0]]);if(c.help){Yr(n,a.action);return}let d=a.action.id??`${n}_${a.action.name.replace(/[-\s]/g,"_")}`;await Jr(d,a.action,c,e)}}var Xr;n_().catch(t=>{t instanceof ue&&(process.stderr.write(t.message+`
|
|
283
283
|
`),process.exit(0)),process.stderr.write(`error: ${t.message}
|
|
284
|
-
`),process.exit(1)}).finally(async()=>{if(!
|
|
284
|
+
`),process.exit(1)}).finally(async()=>{if(!Xr||!process.stderr.isTTY)return;let t=await Xr.catch(()=>"");t&&process.stderr.write(t)});
|
package/dist/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.6
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coinbase-futures
|
|
3
|
+
description: Places and manages CFM dated futures orders on Coinbase Advanced Trade — liquidation risk. Use when the user wants to open a dated futures position, or asks about liquidation risk. Uses the same `coinbase orders`/`coinbase portfolios` commands as spot (see `coinbase-trading`). These are real orders — losses can occur.
|
|
4
|
+
requires: coinbase env configured with Trade permission (see `coinbase` skill)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# coinbase-futures
|
|
8
|
+
|
|
9
|
+
CFM dated futures orders use the same `coinbase orders create` / `orders preview` commands as spot (see `coinbase-trading` for the shared market/limit/stop_limit mechanics and order-management commands). This skill covers what's different for CFM.
|
|
10
|
+
|
|
11
|
+
**Portfolio scope**: CFM dated futures are documented as available only in the caller's default portfolio for now. Pass the default portfolio_uuid (equal to the user's UUID — see `coinbase-trading`) rather than a named sub-portfolio for any futures order.
|
|
12
|
+
|
|
13
|
+
**Product IDs**: `<BASE>-<DDMMMYY>-CDE`, e.g. `BIT-28AUG26-CDE` (Bitcoin) or `BIP-20DEC30-CDE` (a separate Bitcoin-linked contract series — note the ticker root is `BIP`, not `BTC`). These roll to a new contract code every cycle — don't hardcode a date-coded ticker long-term; discover the live one with `coinbase products list product_type=FUTURE` and filter by the `-CDE` suffix.
|
|
14
|
+
|
|
15
|
+
## Market orders: `base_size` only, and can fail after acceptance
|
|
16
|
+
|
|
17
|
+
Futures market orders **must use `base_size`** (number of contracts) — `quote_size` is rejected with `"Futures market orders must be parameterized in base (number of contracts)"`. A market order can also be accepted (an `order_id` is returned) and then transition to `FAILED` asynchronously — not something the CLI can detect at submission time. For a reliable, immediate-fill order, prefer an IOC limit at/above the ask (buy) or at/below the bid (sell) instead of a plain market order:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
coinbase orders create product_id=BIT-28AUG26-CDE side=BUY type=limit base_size=1 limit_price=65000 \
|
|
21
|
+
time_in_force=IOC
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
CFM's margin/leverage is fixed by the exchange per contract, not user-selectable per order — there's no `leverage`/`margin_type` param for orders.
|
|
25
|
+
|
|
26
|
+
**Before placing an order, preview it and read back `predicted_liquidation_price`** — check current position risk from `portfolios get` alongside it, and confirm with the user if margin looks tight:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
coinbase orders preview product_id=BIT-28AUG26-CDE side=BUY type=limit base_size=1 limit_price=65000
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Checking liquidation risk
|
|
33
|
+
|
|
34
|
+
`coinbase portfolios get <portfolio_uuid>` includes `futures_positions` alongside spot.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
coinbase portfolios get <portfolio_uuid> --jq '.futures_positions'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Everything else
|
|
41
|
+
|
|
42
|
+
Sizing (`quote_size`/`base_size`), order types, preview, edit, cancel, and fills work exactly as for spot — see `coinbase-trading`. `reduce_only` is not yet supported for CFM orders through this tool.
|
|
@@ -48,4 +48,4 @@ coinbase products list --jq '.products[].product_id' --paginate
|
|
|
48
48
|
## Notes
|
|
49
49
|
|
|
50
50
|
- For streaming/conditional reads ("tell me when BTC > 65k"), use `coinbase-watch` (`--until`), not polling loops.
|
|
51
|
-
- Market data is read-only and does not place orders. To act on a price, hand off to `coinbase-trading
|
|
51
|
+
- Market data is read-only and does not place orders. To act on a price, hand off to `coinbase-trading` (spot) or `coinbase-futures` (CFM dated futures).
|
|
@@ -25,6 +25,8 @@ coinbase portfolios edit <portfolio_uuid> name="Renamed"
|
|
|
25
25
|
coinbase portfolios delete <portfolio_uuid>
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`portfolios get` includes `futures_positions` alongside spot for any portfolio holding CFM dated-futures positions — see `coinbase-futures` for placing futures orders and reading liquidation risk.
|
|
29
|
+
|
|
28
30
|
## The per-key scoping model
|
|
29
31
|
|
|
30
32
|
Each CDP API key is scoped to ONE portfolio — the key can only trade within it. To operate across portfolios, register one env per portfolio using the `live-<portfolio>` convention:
|