@gala-chain/gswap-sdk 2.0.0-rc.0 → 2.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Gateway. Swap requests are queued for later application.
11
11
  npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next
12
12
  ```
13
13
 
14
- `@gala-chain/gala-core-sdk` is a peer dependency (range `>=1.0.0-rc.4 <2`):
14
+ `@gala-chain/gala-core-sdk` is a peer dependency (range `>=1.0.0-rc.6 <2`):
15
15
  install it next to the SDK. 2.0 is a release candidate under the `next`
16
16
  dist-tag; `latest` is still 1.2.0, so an install without `@next` gets 1.x.
17
17
  Pin exact versions for a wallet or app build.
@@ -73,6 +73,19 @@ const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W');
73
73
  const season = await gSwap.leaderboard.getCurrentSeason(); // null between seasons
74
74
  ```
75
75
 
76
+ ## Onramper widget URL
77
+
78
+ `gSwap.onramper.generateWidgetUrl(request)` asks the swap backend for a signed Onramper (fiat
79
+ on-ramp) widget URL. The route is public: the request carries no `Authorization` header. An app that
80
+ needs only this builds the small service without a whole client:
81
+
82
+ ```typescript
83
+ import { createOnramper } from '@gala-chain/gswap-sdk';
84
+
85
+ const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' });
86
+ const url = await onramper.generateWidgetUrl({ walletAddress: '0x…', defaultCrypto: 'gala', mode: 'buy' });
87
+ ```
88
+
76
89
  ## Hosts and environment presets
77
90
 
78
91
  The SDK has one network boundary: the swap backend. It does not call public
@@ -1,2 +1,2 @@
1
- import{GSwapSDKError as e,getObjectProperty as t}from"./gswap_sdk_error.js";import{validateWalletAddress as n}from"../utils/validation.js";var r=class{constructor(e,t){this.dexBackendBaseUrl=e,this.httpClient=t}async getUserAssets(t,r=1,a=10){if(n(t),!Number.isInteger(r)||r<1)throw new e(`INVALID_PAGE`,{value:r});if(!Number.isInteger(a)||a<1||a>100)throw new e(`INVALID_LIMIT`,{value:a,min:1,max:100});return i(await this.httpClient.sendGetRequest(this.dexBackendBaseUrl,`/user/assets`,``,{address:t,page:r.toString(),limit:a.toString()}))}};function i(n){let r=t(n,`data`),i=r?.token;if(!Array.isArray(i)||!i.every(a))throw new e(`INVALID_CHAIN_RESPONSE`,{resource:`user assets response`},{body:n,write:!1});let o=r?.count;return{tokens:i.map(e=>({...e,decimals:parseInt(e.decimals,10)})),count:typeof o==`number`?o:0}}function a(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.image==`string`&&typeof t.name==`string`&&typeof t.decimals==`string`&&/^\d+$/u.test(t.decimals)&&typeof t.verify==`boolean`&&typeof t.symbol==`string`&&typeof t.quantity==`string`}export{r as Assets};
1
+ import{GSwapSDKError as e,getObjectProperty as t}from"./gswap_sdk_error.js";import{requireUserRef as n}from"../utils/validation.js";var r=class{constructor(e,t){this.dexBackendBaseUrl=e,this.httpClient=t}async getUserAssets(t,r=1,a=10){let o=n(t,`walletAddress`);if(!Number.isInteger(r)||r<1)throw new e(`INVALID_PAGE`,{value:r});if(!Number.isInteger(a)||a<1||a>100)throw new e(`INVALID_LIMIT`,{value:a,min:1,max:100});return i(await this.httpClient.sendGetRequest(this.dexBackendBaseUrl,`/user/assets`,``,{address:o,page:r.toString(),limit:a.toString()}))}};function i(n){let r=t(n,`data`),i=r?.token;if(!Array.isArray(i)||!i.every(a))throw new e(`INVALID_CHAIN_RESPONSE`,{resource:`user assets response`},{body:n,write:!1});let o=r?.count;return{tokens:i.map(e=>({...e,decimals:parseInt(e.decimals,10)})),count:typeof o==`number`?o:0}}function a(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.image==`string`&&typeof t.name==`string`&&typeof t.decimals==`string`&&/^\d+$/u.test(t.decimals)&&typeof t.verify==`boolean`&&typeof t.symbol==`string`&&typeof t.quantity==`string`}export{r as Assets};
2
2
  //# sourceMappingURL=assets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assets.js","names":["Assets","dexBackendBaseUrl","httpClient","validateWalletAddress","ownerAddress","page","GSwapSDKError","limit","parseUserAssets","data","getObjectProperty","value","tokens","\"token\"","isRawUserAsset","count","\"count\"","token","entry","\"image\"","\"name\"","\"decimals\"","\"verify\"","\"symbol\"","\"quantity\""],"sources":["../../../src/classes/assets.ts"],"sourcesContent":["import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { validateWalletAddress } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n validateWalletAddress(ownerAddress);\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address: ownerAddress, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value, write: false },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n"],"mappings":"2IASA,IAAaA,EAAb,KAAoB,CAClB,YACE,EACA,EACA,CAFiB,KAAA,kBAAAC,EACA,KAAA,WAAAC,CAChB,CAiBH,MAAM,cACJ,EACA,EAAe,EACf,EAAgB,GACW,CAG3B,GAFAC,EAAsBC,CAAY,EAE9B,CAAC,OAAO,UAAUC,CAAI,GAAKA,EAAO,EACpC,MAAM,IAAIC,EAAc,eAAgB,CAAE,MAAOD,CAAK,CAAC,EAGzD,GAAI,CAAC,OAAO,UAAUE,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,IACnD,MAAM,IAAID,EAAc,gBAAiB,CAAE,MAAOC,EAAO,IAAK,EAAG,IAAK,GAAI,CAAC,EAS7E,OAAOC,EAAgB,MANK,KAAK,WAAW,eAC1C,KAAK,kBACL,eACA,GACA,CAAE,QAASJ,EAAc,KAAMC,EAAK,SAAS,EAAG,MAAOE,EAAM,SAAS,CAAE,CAC1E,CAC2B,CAC7B,CACF,EAEA,SAASC,EAAgB,EAAkC,CACzD,IAAMC,EAAOC,EAAkBC,EAAO,MAAM,EAGtCC,EAAkBH,GAAOI,MAC/B,GAAI,CAAC,MAAM,QAAQD,CAAM,GAAK,CAACA,EAAO,MAAME,CAAc,EACxD,MAAM,IAAIR,EACR,yBACA,CAAE,SAAU,sBAAuB,EACnC,CAAE,KAAMK,EAAO,MAAO,EAAM,CAC9B,EAEF,IAAMI,EAAQN,GAAOO,MACrB,MAAO,CACL,OAAQJ,EAAO,IAAK,IAAW,CAAE,GAAGK,EAAO,SAAU,SAASA,EAAM,SAAU,EAAE,CAAE,EAAE,EACpF,MAAO,OAAOF,GAAU,SAAWA,EAAQ,CAC7C,CACF,CAIA,SAASD,EAAe,EAAuC,CAC7D,GAAI,OAAOH,GAAU,WAAYA,EAAgB,MAAO,GACxD,IAAMO,EAAQP,EACd,OACE,OAAOO,EAAMC,OAAa,UAC1B,OAAOD,EAAME,MAAY,UACzB,OAAOF,EAAMG,UAAgB,UAC7B,SAAS,KAAKH,EAAMG,QAAW,GAC/B,OAAOH,EAAMI,QAAc,WAC3B,OAAOJ,EAAMK,QAAc,UAC3B,OAAOL,EAAMM,UAAgB,QAEjC"}
1
+ {"version":3,"file":"assets.js","names":["Assets","dexBackendBaseUrl","httpClient","address","requireUserRef","ownerAddress","page","GSwapSDKError","limit","parseUserAssets","data","getObjectProperty","value","tokens","\"token\"","isRawUserAsset","count","\"count\"","token","entry","\"image\"","\"name\"","\"decimals\"","\"verify\"","\"symbol\"","\"quantity\""],"sources":["../../../src/classes/assets.ts"],"sourcesContent":["import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { requireUserRef } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n const address = requireUserRef(ownerAddress, 'walletAddress');\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value, write: false },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n"],"mappings":"oIASA,IAAaA,EAAb,KAAoB,CAClB,YACE,EACA,EACA,CAFiB,KAAA,kBAAAC,EACA,KAAA,WAAAC,CAChB,CAiBH,MAAM,cACJ,EACA,EAAe,EACf,EAAgB,GACW,CAC3B,IAAMC,EAAUC,EAAeC,EAAc,eAAe,EAE5D,GAAI,CAAC,OAAO,UAAUC,CAAI,GAAKA,EAAO,EACpC,MAAM,IAAIC,EAAc,eAAgB,CAAE,MAAOD,CAAK,CAAC,EAGzD,GAAI,CAAC,OAAO,UAAUE,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,IACnD,MAAM,IAAID,EAAc,gBAAiB,CAAE,MAAOC,EAAO,IAAK,EAAG,IAAK,GAAI,CAAC,EAS7E,OAAOC,EAAgB,MANK,KAAK,WAAW,eAC1C,KAAK,kBACL,eACA,GACA,CAAE,UAAS,KAAMH,EAAK,SAAS,EAAG,MAAOE,EAAM,SAAS,CAAE,CAC5D,CAC2B,CAC7B,CACF,EAEA,SAASC,EAAgB,EAAkC,CACzD,IAAMC,EAAOC,EAAkBC,EAAO,MAAM,EAGtCC,EAAkBH,GAAOI,MAC/B,GAAI,CAAC,MAAM,QAAQD,CAAM,GAAK,CAACA,EAAO,MAAME,CAAc,EACxD,MAAM,IAAIR,EACR,yBACA,CAAE,SAAU,sBAAuB,EACnC,CAAE,KAAMK,EAAO,MAAO,EAAM,CAC9B,EAEF,IAAMI,EAAQN,GAAOO,MACrB,MAAO,CACL,OAAQJ,EAAO,IAAK,IAAW,CAAE,GAAGK,EAAO,SAAU,SAASA,EAAM,SAAU,EAAE,CAAE,EAAE,EACpF,MAAO,OAAOF,GAAU,SAAWA,EAAQ,CAC7C,CACF,CAIA,SAASD,EAAe,EAAuC,CAC7D,GAAI,OAAOH,GAAU,WAAYA,EAAgB,MAAO,GACxD,IAAMO,EAAQP,EACd,OACE,OAAOO,EAAMC,OAAa,UAC1B,OAAOD,EAAME,MAAY,UACzB,OAAOF,EAAMG,UAAgB,UAC7B,SAAS,KAAKH,EAAMG,QAAW,GAC/B,OAAOH,EAAMI,QAAc,WAC3B,OAAOJ,EAAMK,QAAc,UAC3B,OAAOL,EAAMM,UAAgB,QAEjC"}
@@ -1,2 +1,2 @@
1
- import{serverMessageOfBody as e}from"../utils/server_message.js";import t from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,getObjectProperty as r,getStringProperty as i,isGSwapError as a}from"./gswap_sdk_error.js";import{shadowFailures as o}from"../utils/shadow_errors.js";import{SubmittedTransaction as s}from"./submitted_transaction.js";import{buildRequestHeaders as c,fetchRequestor as l,readBlockNumberHeader as u,readHeader as d,readResponseBody as f,readRetryAfter as p,requestWithTimeout as m,validateTimeoutMs as h}from"@gala-chain/gala-core-sdk";var g=class{constructor(e){t(this,`requestor`,void 0),t(this,`walletAddress`,void 0),t(this,`chainCallTimeoutMs`,void 0),t(this,`isTransportFailure`,void 0),t(this,`answerOfRejectionHook`,void 0),t(this,`requestTimeoutMs`,void 0),t(this,`dexBackendBaseUrl`,void 0),t(this,`wire`,void 0),this.dexBackendBaseUrl=_(e.dexBackendBaseUrl),this.requestor=e.httpRequestor??l,this.walletAddress=e.walletAddress,this.chainCallTimeoutMs=h(e.chainCallTimeoutMs??3e4,`chainCallTimeoutMs`),this.requestTimeoutMs=this.chainCallTimeoutMs,this.wire=e.wire??{},this.isTransportFailure=e.isTransportFailure,this.answerOfRejectionHook=e.answerOfRejection}async submit(t,r,a){if(t===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:t});let o=this.writeUrl(t),l=a?.walletAddress??this.walletAddress,f=c(this.wire,{json:!0,fixed:l===void 0?{}:{"X-Wallet-Address":l}}),{response:p,body:m}=await this.post(t,o,f,r),h=i(r,`uniqueKey`)??``,g=v(p,m,o,h);if(!p.ok)throw b(p,m,o,h);let _=x(m);if(_?.error===!0)throw new n(`GATEWAY_REPORTED_ERROR`,{serverMessage:e(_)},g);let C=x(_?.data??_?.Data);if(C===void 0)throw new n(`GATEWAY_DATA_MISSING`,{},g);let w=i(C,`transactionId`),T=i(C,`mode`),E=C.transactionId,D=C.blockNumber,O=()=>new n(`GATEWAY_MODE_INVALID`,{},g);if(T!==`sync`&&T!==`queued`||`transactionId`in C&&typeof E!=`string`||D!=null&&!S(D))throw O();if(t===`RequestTrade`&&T===`sync`)throw new n(`GATEWAY_SYNC_REQUEST_TRADE`,{},g);if(t===`RequestTrade`&&T===`queued`)y(p,m,o,C,r);else if(T===`queued`||!(`result`in C))throw O();if(T===`sync`){let e=x(C.result);if(e!==void 0){let t=e.Status;if(t!==void 0&&t!==1)throw n.fromChainError(i(e,`ErrorKey`)??`CHAIN_ERROR`,i(e,`Message`)??``,g)}}let k=d(p,`x-transaction-id`),A=w===void 0||w===``?k:w,j=D==null?u(p):S(D)?D:void 0;return new s({method:t,uniqueKey:h,transactionId:A===void 0||A===``?null:A,blockNumber:j??null,mode:T,result:T===`queued`?void 0:C.result,envelope:m,dexBackendBaseUrl:this.dexBackendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.chainCallTimeoutMs,wire:this.wire,...a?.positionConfirmation===void 0?{}:{positionConfirmation:a.positionConfirmation}})}async submitShadow(e,t,n){return o(()=>this.sendShadow(e,t,n))}async sendShadow(e,t,r){if(e===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:e});let i=r?.walletAddress??this.walletAddress;if(i===void 0)throw new n(`SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS`,{});let a=c(this.wire,{json:!0,fixed:{"X-Wallet-Address":i,"X-Shadow":`true`}}),{response:o,body:s}=await this.post(e,this.writeUrl(e),a,t);return{httpStatus:o.status,body:s}}writeUrl(e){return`${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${e}`}async post(e,t,r,o){let s;try{s=JSON.stringify(o)}catch(t){throw new n(`SIGNING_FAILED`,{method:e,reason:`failed`},{cause:t})}let c=(e,r)=>new n(`SUBMISSION_OUTCOME_UNKNOWN`,{reason:e},{uniqueKey:i(o,`uniqueKey`)??``,url:t,cause:r}),l;try{l=await m(this.requestor,t,{method:`POST`,headers:r,body:s},this.chainCallTimeoutMs)}catch(e){if(a(e,`REQUEST_TIMEOUT`))throw c(`timeout`,e);if(a(e,`TRANSPORT_ERROR`)||this.isTransportRejection(e))throw c(`transport`,e);let t=this.answerOfRejection(e);if(t!==void 0)return t;throw e}try{return{response:l,body:await f(l)}}catch(e){throw c(`transport`,e)}}answerOfRejection(e){let t;try{t=this.answerOfRejectionHook?.(e)}catch{return}if(t===void 0)return;let{status:n,body:r,headers:i}=t;if(!Number.isInteger(n)||n<100||n>599)return;let a=typeof r==`string`?r:``;return{response:{ok:n>=200&&n<300,status:n,json:async()=>r,text:async()=>a,headers:i??{}},body:r}}isTransportRejection(e){try{return this.isTransportFailure?.(e)===!0}catch{return!1}}get httpRequestor(){return this.requestor}};function _(e){return e.replace(/\/$/u,``)}function v(e,t,n,r){return{status:e.status,body:t,url:n,...r===void 0||r===``?{}:{uniqueKey:r}}}function y(e,t,r,a,o){let s=i(o,`uniqueKey`)??``,c=a.uniqueKey;if(typeof c==`string`&&c!==``&&c===s)return;let l=c==null||c===``,u={...v(e,t,r),uniqueKey:s};throw l?new n(`MISSING_UNIQUE_KEY`,{},u):new n(`UNIQUE_KEY_MISMATCH`,{},u)}function b(t,a,o,s){if(t.status===426)return new n(`UPDATE_REQUIRED`,{status:t.status},v(t,a,o,s));let c=x(a),l=r(a,`error`),u=i(c,`code`)??i(l,`code`)??i(l,`ErrorKey`)??`HTTP_ERROR`,d=e(a),f=t.status===429?p(t):void 0;return u===`HTTP_ERROR`?new n(`HTTP_ERROR`,{status:t.status,url:o,serverMessage:d},v(t,a,o,s)):n.fromGatewayBounce(u,d,t.status,a,o,f,s===``?void 0:s)}function x(e){return typeof e==`object`&&e?e:void 0}function S(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}export{g as ChainGateway};
1
+ import{serverMessageOfBody as e}from"../utils/server_message.js";import t from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as n,getObjectProperty as r,getStringProperty as i,isGSwapError as a}from"./gswap_sdk_error.js";import{userRef as o}from"../utils/validation.js";import{shadowFailures as s}from"../utils/shadow_errors.js";import{SubmittedTransaction as c}from"./submitted_transaction.js";import{buildRequestHeaders as l,fetchRequestor as u,readBlockNumberHeader as d,readHeader as f,readResponseBody as p,readRetryAfter as m,requestWithTimeout as h,validateTimeoutMs as g}from"@gala-chain/gala-core-sdk";var _=class{constructor(e){t(this,`requestor`,void 0),t(this,`walletAddress`,void 0),t(this,`chainCallTimeoutMs`,void 0),t(this,`isTransportFailure`,void 0),t(this,`answerOfRejectionHook`,void 0),t(this,`requestTimeoutMs`,void 0),t(this,`dexBackendBaseUrl`,void 0),t(this,`wire`,void 0),this.dexBackendBaseUrl=v(e.dexBackendBaseUrl),this.requestor=e.httpRequestor??u,this.walletAddress=e.walletAddress===void 0?void 0:o(e.walletAddress,`walletAddress`),this.chainCallTimeoutMs=g(e.chainCallTimeoutMs??3e4,`chainCallTimeoutMs`),this.requestTimeoutMs=this.chainCallTimeoutMs,this.wire=e.wire??{},this.isTransportFailure=e.isTransportFailure,this.answerOfRejectionHook=e.answerOfRejection}async submit(t,r,a){if(t===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:t});let o=this.writeUrl(t),s=this.walletOf(a),u=l(this.wire,{json:!0,fixed:s===void 0?{}:{"X-Wallet-Address":s}}),{response:p,body:m}=await this.post(t,o,u,r),h=i(r,`uniqueKey`)??``,g=y(p,m,o,h);if(!p.ok)throw x(p,m,o,h);let _=S(m);if(_?.error===!0)throw new n(`GATEWAY_REPORTED_ERROR`,{serverMessage:e(_)},g);let v=S(_?.data??_?.Data);if(v===void 0)throw new n(`GATEWAY_DATA_MISSING`,{},g);let w=i(v,`transactionId`),T=i(v,`mode`),E=v.transactionId,D=v.blockNumber,O=()=>new n(`GATEWAY_MODE_INVALID`,{},g);if(T!==`sync`&&T!==`queued`||`transactionId`in v&&typeof E!=`string`||D!=null&&!C(D))throw O();if(t===`RequestTrade`&&T===`sync`)throw new n(`GATEWAY_SYNC_REQUEST_TRADE`,{},g);if(t===`RequestTrade`&&T===`queued`)b(p,m,o,v,r);else if(T===`queued`||!(`result`in v))throw O();if(T===`sync`){let e=S(v.result);if(e!==void 0){let t=e.Status;if(t!==void 0&&t!==1)throw n.fromChainError(i(e,`ErrorKey`)??`CHAIN_ERROR`,i(e,`Message`)??``,g)}}let k=f(p,`x-transaction-id`),A=w===void 0||w===``?k:w,j=D==null?d(p):C(D)?D:void 0;return new c({method:t,uniqueKey:h,transactionId:A===void 0||A===``?null:A,blockNumber:j??null,mode:T,result:T===`queued`?void 0:v.result,envelope:m,dexBackendBaseUrl:this.dexBackendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.chainCallTimeoutMs,wire:this.wire,...a?.positionConfirmation===void 0?{}:{positionConfirmation:a.positionConfirmation}})}async submitShadow(e,t,n){return s(()=>this.sendShadow(e,t,n))}async sendShadow(e,t,r){if(e===`Trade`)throw new n(`METHOD_NOT_SUPPORTED`,{method:e});let i=this.walletOf(r);if(i===void 0)throw new n(`SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS`,{});let a=l(this.wire,{json:!0,fixed:{"X-Wallet-Address":i,"X-Shadow":`true`}}),{response:o,body:s}=await this.post(e,this.writeUrl(e),a,t);return{httpStatus:o.status,body:s}}walletOf(e){return e?.walletAddress===void 0?this.walletAddress:o(e.walletAddress,`walletAddress`)}writeUrl(e){return`${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${e}`}async post(e,t,r,o){let s;try{s=JSON.stringify(o)}catch(t){throw new n(`SIGNING_FAILED`,{method:e,reason:`failed`},{cause:t})}let c=(e,r)=>new n(`SUBMISSION_OUTCOME_UNKNOWN`,{reason:e},{uniqueKey:i(o,`uniqueKey`)??``,url:t,cause:r}),l;try{l=await h(this.requestor,t,{method:`POST`,headers:r,body:s},this.chainCallTimeoutMs)}catch(e){if(a(e,`REQUEST_TIMEOUT`))throw c(`timeout`,e);if(a(e,`TRANSPORT_ERROR`)||this.isTransportRejection(e))throw c(`transport`,e);let t=this.answerOfRejection(e);if(t!==void 0)return t;throw e}try{return{response:l,body:await p(l)}}catch(e){throw c(`transport`,e)}}answerOfRejection(e){let t;try{t=this.answerOfRejectionHook?.(e)}catch{return}if(t===void 0)return;let{status:n,body:r,headers:i}=t;if(!Number.isInteger(n)||n<100||n>599)return;let a=typeof r==`string`?r:``;return{response:{ok:n>=200&&n<300,status:n,json:async()=>r,text:async()=>a,headers:i??{}},body:r}}isTransportRejection(e){try{return this.isTransportFailure?.(e)===!0}catch{return!1}}get httpRequestor(){return this.requestor}};function v(e){return e.replace(/\/$/u,``)}function y(e,t,n,r){return{status:e.status,body:t,url:n,...r===void 0||r===``?{}:{uniqueKey:r}}}function b(e,t,r,a,o){let s=i(o,`uniqueKey`)??``,c=a.uniqueKey;if(typeof c==`string`&&c!==``&&c===s)return;let l=c==null||c===``,u={...y(e,t,r),uniqueKey:s};throw l?new n(`MISSING_UNIQUE_KEY`,{},u):new n(`UNIQUE_KEY_MISMATCH`,{},u)}function x(t,a,o,s){if(t.status===426)return new n(`UPDATE_REQUIRED`,{status:t.status},y(t,a,o,s));let c=S(a),l=r(a,`error`),u=i(c,`code`)??i(l,`code`)??i(l,`ErrorKey`)??`HTTP_ERROR`,d=e(a),f=t.status===429?m(t):void 0;return u===`HTTP_ERROR`?new n(`HTTP_ERROR`,{status:t.status,url:o,serverMessage:d},y(t,a,o,s)):n.fromGatewayBounce(u,d,t.status,a,o,f,s===``?void 0:s)}function S(e){return typeof e==`object`&&e?e:void 0}function C(e){return typeof e==`number`&&Number.isInteger(e)&&e>=0}export{_ as ChainGateway};
2
2
  //# sourceMappingURL=gateway.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","names":["_defineProperty","ChainGateway","trimTrailingSlash","options","fetchRequestor","validateTimeoutMs","method","GSwapSDKError","url","walletAddress","headers","buildRequestHeaders","signedBody","uniqueKey","getStringProperty","context","responseContext","response","body","gatewayError","envelope","asRecord","\"error\"","serverMessageOfBody","data","\"data\"","\"Data\"","transactionId","mode","rawTransactionId","\"transactionId\"","bodyBlockNumber","\"blockNumber\"","invalidMode","isBlockNumber","assertQueuedUnderSignedKey","embeddedResult","\"result\"","resultStatus","\"Status\"","headerTransactionId","readHeader","resolvedTransactionId","blockNumber","readBlockNumberHeader","SubmittedTransaction","shadowFailures","payload","cause","outcomeUnknown","requestWithTimeout","error","isGSwapError","answered","readResponseBody","answer","status","text","value","signedUniqueKey","echoed","\"uniqueKey\"","missing","object","nested","getObjectProperty","code","message","retryAfterMs","readRetryAfter"],"sources":["../../../src/classes/gateway.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport type { SubmissionOutcomeUnknownReason } from './gswap_error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress = options.walletAddress;\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so defi-backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = options?.walletAddress ?? this.walletAddress;\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is frontend_v2's: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GalaErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GalaErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n"],"mappings":"kmBA+GA,IAAaC,EAAb,KAA0B,CAexB,YAAY,EAA8B,CAdzBD,EAAA,KAAA,YAAA,IAAA,EAAA,EACAA,EAAA,KAAA,gBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,qBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,qBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,wBAAA,IAAA,EAAA,EAGDA,EAAA,KAAA,mBAAA,IAAA,EAAA,EAEAA,EAAA,KAAA,oBAAA,IAAA,EAAA,EAEAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAId,KAAK,kBAAoBE,EAAkBC,EAAQ,iBAAiB,EACpE,KAAK,UAAYA,EAAQ,eAAiBC,EAC1C,KAAK,cAAgBD,EAAQ,cAC7B,KAAK,mBAAqBE,EACxBF,EAAQ,oBAAsB,IAC9B,oBACF,EACA,KAAK,iBAAmB,KAAK,mBAC7B,KAAK,KAAOA,EAAQ,MAAQ,CAAC,EAC7B,KAAK,mBAAqBA,EAAQ,mBAClC,KAAK,sBAAwBA,EAAQ,iBACvC,CAqBA,MAAa,OACX,EACA,EACA,EAC+B,CAI/B,GAAIG,IAAW,QACb,MAAM,IAAIC,EAAc,uBAAwB,CAAE,QAAO,CAAC,EAE5D,IAAMC,EAAM,KAAK,SAASF,CAAM,EAC1BG,EAAgBN,GAAS,eAAiB,KAAK,cAC/CO,EAAUC,EAAoB,KAAK,KAAM,CAC7C,KAAM,GACN,MAAOF,IAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,mBAAoBA,CAAc,CAChF,CAAC,EACK,CAAE,WAAU,QAAS,MAAM,KAAK,KAAKH,EAAQE,EAAKE,EAASE,CAAU,EAGrEC,EAAYC,EAAkBF,EAAY,WAAW,GAAK,GAC1DG,EAAUC,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,EAE9D,GAAI,CAACI,EAAS,GACZ,MAAME,EAAaF,EAAUC,EAAMV,EAAKK,CAAS,EAGnD,IAAMO,EAAWC,EAASH,CAAI,EAE9B,GAAIE,GAAWE,QAAa,GAC1B,MAAM,IAAIf,EACR,yBACA,CAAE,cAAegB,EAAoBH,CAAQ,CAAE,EAC/CL,CACF,EAEF,IAAMS,EAAOH,EAASD,GAAWK,MAAWL,GAAWM,IAAO,EAC9D,GAAIF,IAAS,IAAA,GACX,MAAM,IAAIjB,EAAc,uBAAwB,CAAC,EAAGQ,CAAO,EAG7D,IAAMY,EAAgBb,EAAkBU,EAAM,eAAe,EACvDI,EAAOd,EAAkBU,EAAM,MAAM,EACrCK,EAAmBL,EAAKM,cACxBC,EAAkBP,EAAKQ,YACvBC,MACJ,IAAI1B,EAAc,uBAAwB,CAAC,EAAGQ,CAAO,EAIvD,GAHIa,IAAS,QAAUA,IAAS,UAI7B,kBAAmBJ,GAAQ,OAAOK,GAAqB,UACvDE,GAAqD,MAAQ,CAACG,EAAcH,CAAe,EAE5F,MAAME,EAAY,EAEpB,GAAI3B,IAAW,gBAAkBsB,IAAS,OACxC,MAAM,IAAIrB,EAAc,6BAA8B,CAAC,EAAGQ,CAAO,EAEnE,GAAIT,IAAW,gBAAkBsB,IAAS,SACxCO,EAA2BlB,EAAUC,EAAMV,EAAKgB,EAAMZ,CAAU,OAC3D,GAAIgB,IAAS,UAAY,EAAE,WAAYJ,GAC5C,MAAMS,EAAY,EAIpB,GAAIL,IAAS,OAAQ,CACnB,IAAMQ,EAAiBf,EAASG,EAAKa,MAAS,EAC9C,GAAID,IAAmB,IAAA,GAAW,CAChC,IAAME,EAAeF,EAAeG,OACpC,GAAID,IAAiB,IAAA,IAAaA,IAAiB,EACjD,MAAM/B,EAAc,eAClBO,EAAkBsB,EAAgB,UAAU,GAAK,cACjDtB,EAAkBsB,EAAgB,SAAS,GAAK,GAChDrB,CACF,CAEJ,CACF,CAEA,IAAMyB,EAAsBC,EAAWxB,EAAU,kBAAkB,EAC7DyB,EACJf,IAAkB,IAAA,IAAaA,IAAkB,GAAKa,EAAsBb,EACxEgB,EACJZ,GAAoB,KAChBa,EAAsB3B,CAAQ,EAC9BiB,EAAcH,CAAe,EAC3BA,EACA,IAAA,GACR,OAAO,IAAIc,EAAqB,CAC9B,SACA,YACA,cACEH,IAA0B,IAAA,IAAaA,IAA0B,GAC7D,KACAA,EACN,YAAaC,GAAe,KAC5B,OACA,OAAQf,IAAS,SAAW,IAAA,GAAYJ,EAAKa,OAC7C,SAAUnB,EACV,kBAAmB,KAAK,kBACxB,cAAe,KAAK,UACpB,iBAAkB,KAAK,mBACvB,KAAM,KAAK,KACX,GAAIf,GAAS,uBAAyB,IAAA,GAClC,CAAC,EACD,CAAE,qBAAsBA,EAAQ,oBAAqB,CAC3D,CAAC,CACH,CAsBA,MAAa,aACX,EACA,EACA,EAC6B,CAC7B,OAAO2C,MAAqB,KAAK,WAAWxC,EAAQM,EAAYT,CAAO,CAAC,CAC1E,CAEA,MAAc,WACZ,EACA,EACA,EAC6B,CAC7B,GAAIG,IAAW,QACb,MAAM,IAAIC,EAAc,uBAAwB,CAAE,QAAO,CAAC,EAE5D,IAAME,EAAgBN,GAAS,eAAiB,KAAK,cACrD,GAAIM,IAAkB,IAAA,GACpB,MAAM,IAAIF,EAAc,qCAAsC,CAAC,CAAC,EAGlE,IAAMG,EAAUC,EAAoB,KAAK,KAAM,CAC7C,KAAM,GACN,MAAO,CAAE,mBAAoBF,EAAe,WAAY,MAAO,CACjE,CAAC,EACK,CAAE,WAAU,QAAS,MAAM,KAAK,KAAKH,EAAQ,KAAK,SAASA,CAAM,EAAGI,EAASE,CAAU,EAC7F,MAAO,CAAE,WAAYK,EAAS,OAAQ,MAAK,CAC7C,CAEA,SAAiB,EAAwB,CACvC,MAAO,GAAG,KAAK,kBAAkB,+BAA+BX,GAClE,CAQA,MAAc,KACZ,EACA,EACA,EACA,EACoD,CAIpD,IAAIyC,EACJ,GAAI,CACF,EAAU,KAAK,UAAUnC,CAAU,CACrC,OAASoC,EAAgB,CACvB,MAAM,IAAIzC,EAAc,iBAAkB,CAAE,SAAQ,OAAQ,QAAS,EAAG,CAAE,OAAM,CAAC,CACnF,CACA,IAAM0C,GACJ,EACA,IAEA,IAAI1C,EACF,6BACA,CAAE,QAAO,EACT,CAAE,UAAWO,EAAkBF,EAAY,WAAW,GAAK,GAAI,MAAK,OAAM,CAC5E,EACEK,EACJ,GAAI,CACF,EAAW,MAAMiC,EACf,KAAK,UACL1C,EACA,CACE,OAAQ,OACR,UACA,KAAMuC,CACR,EACA,KAAK,kBACP,CACF,OAASI,EAAgB,CACvB,GAAIC,EAAaD,EAAO,iBAAiB,EAAG,MAAMF,EAAe,UAAWE,CAAK,EACjF,GAAIC,EAAaD,EAAO,iBAAiB,GAAK,KAAK,qBAAqBA,CAAK,EAC3E,MAAMF,EAAe,YAAaE,CAAK,EAMzC,IAAME,EAAW,KAAK,kBAAkBF,CAAK,EAC7C,GAAIE,IAAa,IAAA,GAAW,OAAOA,EACnC,MAAMF,CACR,CACA,GAAI,CACF,MAAO,CAAE,WAAU,KAAM,MAAMG,EAAiBrC,CAAQ,CAAE,CAC5D,OAASkC,EAAgB,CAGvB,MAAMF,EAAe,YAAaE,CAAK,CACzC,CACF,CAOA,kBAA0B,EAAuE,CAC/F,IAAII,EACJ,GAAI,CACF,EAAS,KAAK,wBAAwBJ,CAAK,CAC7C,MAAQ,CACN,MACF,CACA,GAAII,IAAW,IAAA,GAAW,OAC1B,GAAM,CAAE,SAAQ,OAAM,WAAYA,EAClC,GAAI,CAAC,OAAO,UAAUC,CAAM,GAAKA,EAAS,KAAOA,EAAS,IAAK,OAC/D,IAAMC,EAAO,OAAOvC,GAAS,SAAWA,EAAO,GAQ/C,MAAO,CAAE,SAAA,CANP,GAAIsC,GAAU,KAAOA,EAAS,IAC9B,SACA,KAAM,SAAYtC,EAClB,KAAM,SAAYuC,EAClB,QAAS/C,GAAW,CAAC,CAEP,EAAG,MAAK,CAC1B,CAEA,qBAA6B,EAAyB,CACpD,GAAI,CACF,OAAO,KAAK,qBAAqByC,CAAK,IAAM,EAC9C,MAAQ,CACN,MAAO,EACT,CACF,CAGA,IAAW,eAA+B,CACxC,OAAO,KAAK,SACd,CACF,EAEA,SAASjD,EAAkB,EAAuB,CAChD,OAAOwD,EAAM,QAAQ,OAAQ,EAAE,CACjC,CAEA,SAAS1C,EACP,EACA,EACA,EACA,EACkB,CAClB,MAAO,CACL,OAAQC,EAAS,OACjB,OACA,MACA,GAAIJ,IAAc,IAAA,IAAaA,IAAc,GAAK,CAAC,EAAI,CAAE,WAAU,CACrE,CACF,CAYA,SAASsB,EACP,EACA,EACA,EACA,EACA,EACM,CACN,IAAMwB,EAAkB7C,EAAkBF,EAAY,WAAW,GAAK,GAChEgD,EAASpC,EAAKqC,UACpB,GAAI,OAAOD,GAAW,UAAYA,IAAW,IAAMA,IAAWD,EAAiB,OAC/E,IAAMG,EAAUF,GAAmC,MAAQA,IAAW,GAChE7C,EAA4B,CAChC,GAAGC,EAAgBC,EAAUC,EAAMV,CAAG,EACtC,UAAWmD,CACb,EACA,MAAMG,EACF,IAAIvD,EAAc,qBAAsB,CAAC,EAAGQ,CAAO,EACnD,IAAIR,EAAc,sBAAuB,CAAC,EAAGQ,CAAO,CAC1D,CAEA,SAASI,EACP,EACA,EACA,EACA,EACe,CAEf,GAAIF,EAAS,SAAA,IACX,OAAO,IAAIV,EACT,kBACA,CAAE,OAAQU,EAAS,MAAO,EAC1BD,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,CAChD,EAEF,IAAMkD,EAAS1C,EAASH,CAAI,EACtB8C,EAASC,EAAkB/C,EAAM,OAAO,EACxCgD,EACJpD,EAAkBiD,EAAQ,MAAM,GAChCjD,EAAkBkD,EAAQ,MAAM,GAChClD,EAAkBkD,EAAQ,UAAU,GACpC,aAGIG,EAAU5C,EAAoBL,CAAI,EAClCkD,EAAenD,EAAS,SAAW,IAAMoD,EAAepD,CAAQ,EAAI,IAAA,GAQ1E,OAPIiD,IAAS,aACJ,IAAI3D,EACT,aACA,CAAE,OAAQU,EAAS,OAAQ,MAAK,cAAekD,CAAQ,EACvDnD,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,CAChD,EAEKN,EAAc,kBACnB2D,EACAC,EACAlD,EAAS,OACTC,EACAV,EACA4D,EACAvD,IAAc,GAAK,IAAA,GAAYA,CACjC,CACF,CAEA,SAASQ,EAAS,EAAqD,CACrE,OAAO,OAAOqC,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN,CAEA,SAASxB,EAAc,EAAiC,CACtD,OAAO,OAAOwB,GAAU,UAAY,OAAO,UAAUA,CAAK,GAAKA,GAAS,CAC1E"}
1
+ {"version":3,"file":"gateway.js","names":["_defineProperty","ChainGateway","trimTrailingSlash","options","fetchRequestor","userRef","validateTimeoutMs","method","GSwapSDKError","url","walletAddress","headers","buildRequestHeaders","signedBody","uniqueKey","getStringProperty","context","responseContext","response","body","gatewayError","envelope","asRecord","\"error\"","serverMessageOfBody","data","\"data\"","\"Data\"","transactionId","mode","rawTransactionId","\"transactionId\"","bodyBlockNumber","\"blockNumber\"","invalidMode","isBlockNumber","assertQueuedUnderSignedKey","embeddedResult","\"result\"","resultStatus","\"Status\"","headerTransactionId","readHeader","resolvedTransactionId","blockNumber","readBlockNumberHeader","SubmittedTransaction","shadowFailures","payload","cause","outcomeUnknown","requestWithTimeout","error","isGSwapError","answered","readResponseBody","answer","status","text","value","signedUniqueKey","echoed","\"uniqueKey\"","missing","object","nested","getObjectProperty","code","message","retryAfterMs","readRetryAfter"],"sources":["../../../src/classes/gateway.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport { userRef } from '../utils/validation.js';\nimport type { SubmissionOutcomeUnknownReason } from './gswap_error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress =\n options.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = this.walletOf(options);\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so defi-backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = this.walletOf(options);\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is frontend_v2's: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n /**\n * The `X-Wallet-Address` of a write: the per-call wallet or the gateway's, in the gateway's\n * spelling (`eth|<EIP-55>`, `client|<id>` as written). A per-call wallet that is no user\n * reference is refused before anything is sent.\n */\n private walletOf(options: ChainSubmitOptions | undefined): string | undefined {\n return options?.walletAddress === undefined\n ? this.walletAddress\n : userRef(options.walletAddress, 'walletAddress');\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GalaErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GalaErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n"],"mappings":"mpBAgHA,IAAaC,EAAb,KAA0B,CAexB,YAAY,EAA8B,CAdzBD,EAAA,KAAA,YAAA,IAAA,EAAA,EACAA,EAAA,KAAA,gBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,qBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,qBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,wBAAA,IAAA,EAAA,EAGDA,EAAA,KAAA,mBAAA,IAAA,EAAA,EAEAA,EAAA,KAAA,oBAAA,IAAA,EAAA,EAEAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAId,KAAK,kBAAoBE,EAAkBC,EAAQ,iBAAiB,EACpE,KAAK,UAAYA,EAAQ,eAAiBC,EAC1C,KAAK,cACHD,EAAQ,gBAAkB,IAAA,GACtB,IAAA,GACAE,EAAQF,EAAQ,cAAe,eAAe,EACpD,KAAK,mBAAqBG,EACxBH,EAAQ,oBAAsB,IAC9B,oBACF,EACA,KAAK,iBAAmB,KAAK,mBAC7B,KAAK,KAAOA,EAAQ,MAAQ,CAAC,EAC7B,KAAK,mBAAqBA,EAAQ,mBAClC,KAAK,sBAAwBA,EAAQ,iBACvC,CAqBA,MAAa,OACX,EACA,EACA,EAC+B,CAI/B,GAAII,IAAW,QACb,MAAM,IAAIC,EAAc,uBAAwB,CAAE,QAAO,CAAC,EAE5D,IAAMC,EAAM,KAAK,SAASF,CAAM,EAC1BG,EAAgB,KAAK,SAASP,CAAO,EACrCQ,EAAUC,EAAoB,KAAK,KAAM,CAC7C,KAAM,GACN,MAAOF,IAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,mBAAoBA,CAAc,CAChF,CAAC,EACK,CAAE,WAAU,QAAS,MAAM,KAAK,KAAKH,EAAQE,EAAKE,EAASE,CAAU,EAGrEC,EAAYC,EAAkBF,EAAY,WAAW,GAAK,GAC1DG,EAAUC,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,EAE9D,GAAI,CAACI,EAAS,GACZ,MAAME,EAAaF,EAAUC,EAAMV,EAAKK,CAAS,EAGnD,IAAMO,EAAWC,EAASH,CAAI,EAE9B,GAAIE,GAAWE,QAAa,GAC1B,MAAM,IAAIf,EACR,yBACA,CAAE,cAAegB,EAAoBH,CAAQ,CAAE,EAC/CL,CACF,EAEF,IAAMS,EAAOH,EAASD,GAAWK,MAAWL,GAAWM,IAAO,EAC9D,GAAIF,IAAS,IAAA,GACX,MAAM,IAAIjB,EAAc,uBAAwB,CAAC,EAAGQ,CAAO,EAG7D,IAAMY,EAAgBb,EAAkBU,EAAM,eAAe,EACvDI,EAAOd,EAAkBU,EAAM,MAAM,EACrCK,EAAmBL,EAAKM,cACxBC,EAAkBP,EAAKQ,YACvBC,MACJ,IAAI1B,EAAc,uBAAwB,CAAC,EAAGQ,CAAO,EAIvD,GAHIa,IAAS,QAAUA,IAAS,UAI7B,kBAAmBJ,GAAQ,OAAOK,GAAqB,UACvDE,GAAqD,MAAQ,CAACG,EAAcH,CAAe,EAE5F,MAAME,EAAY,EAEpB,GAAI3B,IAAW,gBAAkBsB,IAAS,OACxC,MAAM,IAAIrB,EAAc,6BAA8B,CAAC,EAAGQ,CAAO,EAEnE,GAAIT,IAAW,gBAAkBsB,IAAS,SACxCO,EAA2BlB,EAAUC,EAAMV,EAAKgB,EAAMZ,CAAU,OAC3D,GAAIgB,IAAS,UAAY,EAAE,WAAYJ,GAC5C,MAAMS,EAAY,EAIpB,GAAIL,IAAS,OAAQ,CACnB,IAAMQ,EAAiBf,EAASG,EAAKa,MAAS,EAC9C,GAAID,IAAmB,IAAA,GAAW,CAChC,IAAME,EAAeF,EAAeG,OACpC,GAAID,IAAiB,IAAA,IAAaA,IAAiB,EACjD,MAAM/B,EAAc,eAClBO,EAAkBsB,EAAgB,UAAU,GAAK,cACjDtB,EAAkBsB,EAAgB,SAAS,GAAK,GAChDrB,CACF,CAEJ,CACF,CAEA,IAAMyB,EAAsBC,EAAWxB,EAAU,kBAAkB,EAC7DyB,EACJf,IAAkB,IAAA,IAAaA,IAAkB,GAAKa,EAAsBb,EACxEgB,EACJZ,GAAoB,KAChBa,EAAsB3B,CAAQ,EAC9BiB,EAAcH,CAAe,EAC3BA,EACA,IAAA,GACR,OAAO,IAAIc,EAAqB,CAC9B,SACA,YACA,cACEH,IAA0B,IAAA,IAAaA,IAA0B,GAC7D,KACAA,EACN,YAAaC,GAAe,KAC5B,OACA,OAAQf,IAAS,SAAW,IAAA,GAAYJ,EAAKa,OAC7C,SAAUnB,EACV,kBAAmB,KAAK,kBACxB,cAAe,KAAK,UACpB,iBAAkB,KAAK,mBACvB,KAAM,KAAK,KACX,GAAIhB,GAAS,uBAAyB,IAAA,GAClC,CAAC,EACD,CAAE,qBAAsBA,EAAQ,oBAAqB,CAC3D,CAAC,CACH,CAsBA,MAAa,aACX,EACA,EACA,EAC6B,CAC7B,OAAO4C,MAAqB,KAAK,WAAWxC,EAAQM,EAAYV,CAAO,CAAC,CAC1E,CAEA,MAAc,WACZ,EACA,EACA,EAC6B,CAC7B,GAAII,IAAW,QACb,MAAM,IAAIC,EAAc,uBAAwB,CAAE,QAAO,CAAC,EAE5D,IAAME,EAAgB,KAAK,SAASP,CAAO,EAC3C,GAAIO,IAAkB,IAAA,GACpB,MAAM,IAAIF,EAAc,qCAAsC,CAAC,CAAC,EAGlE,IAAMG,EAAUC,EAAoB,KAAK,KAAM,CAC7C,KAAM,GACN,MAAO,CAAE,mBAAoBF,EAAe,WAAY,MAAO,CACjE,CAAC,EACK,CAAE,WAAU,QAAS,MAAM,KAAK,KAAKH,EAAQ,KAAK,SAASA,CAAM,EAAGI,EAASE,CAAU,EAC7F,MAAO,CAAE,WAAYK,EAAS,OAAQ,MAAK,CAC7C,CAOA,SAAiB,EAA6D,CAC5E,OAAOf,GAAS,gBAAkB,IAAA,GAC9B,KAAK,cACLE,EAAQF,EAAQ,cAAe,eAAe,CACpD,CAEA,SAAiB,EAAwB,CACvC,MAAO,GAAG,KAAK,kBAAkB,+BAA+BI,GAClE,CAQA,MAAc,KACZ,EACA,EACA,EACA,EACoD,CAIpD,IAAIyC,EACJ,GAAI,CACF,EAAU,KAAK,UAAUnC,CAAU,CACrC,OAASoC,EAAgB,CACvB,MAAM,IAAIzC,EAAc,iBAAkB,CAAE,SAAQ,OAAQ,QAAS,EAAG,CAAE,OAAM,CAAC,CACnF,CACA,IAAM0C,GACJ,EACA,IAEA,IAAI1C,EACF,6BACA,CAAE,QAAO,EACT,CAAE,UAAWO,EAAkBF,EAAY,WAAW,GAAK,GAAI,MAAK,OAAM,CAC5E,EACEK,EACJ,GAAI,CACF,EAAW,MAAMiC,EACf,KAAK,UACL1C,EACA,CACE,OAAQ,OACR,UACA,KAAMuC,CACR,EACA,KAAK,kBACP,CACF,OAASI,EAAgB,CACvB,GAAIC,EAAaD,EAAO,iBAAiB,EAAG,MAAMF,EAAe,UAAWE,CAAK,EACjF,GAAIC,EAAaD,EAAO,iBAAiB,GAAK,KAAK,qBAAqBA,CAAK,EAC3E,MAAMF,EAAe,YAAaE,CAAK,EAMzC,IAAME,EAAW,KAAK,kBAAkBF,CAAK,EAC7C,GAAIE,IAAa,IAAA,GAAW,OAAOA,EACnC,MAAMF,CACR,CACA,GAAI,CACF,MAAO,CAAE,WAAU,KAAM,MAAMG,EAAiBrC,CAAQ,CAAE,CAC5D,OAASkC,EAAgB,CAGvB,MAAMF,EAAe,YAAaE,CAAK,CACzC,CACF,CAOA,kBAA0B,EAAuE,CAC/F,IAAII,EACJ,GAAI,CACF,EAAS,KAAK,wBAAwBJ,CAAK,CAC7C,MAAQ,CACN,MACF,CACA,GAAII,IAAW,IAAA,GAAW,OAC1B,GAAM,CAAE,SAAQ,OAAM,WAAYA,EAClC,GAAI,CAAC,OAAO,UAAUC,CAAM,GAAKA,EAAS,KAAOA,EAAS,IAAK,OAC/D,IAAMC,EAAO,OAAOvC,GAAS,SAAWA,EAAO,GAQ/C,MAAO,CAAE,SAAA,CANP,GAAIsC,GAAU,KAAOA,EAAS,IAC9B,SACA,KAAM,SAAYtC,EAClB,KAAM,SAAYuC,EAClB,QAAS/C,GAAW,CAAC,CAEP,EAAG,MAAK,CAC1B,CAEA,qBAA6B,EAAyB,CACpD,GAAI,CACF,OAAO,KAAK,qBAAqByC,CAAK,IAAM,EAC9C,MAAQ,CACN,MAAO,EACT,CACF,CAGA,IAAW,eAA+B,CACxC,OAAO,KAAK,SACd,CACF,EAEA,SAASlD,EAAkB,EAAuB,CAChD,OAAOyD,EAAM,QAAQ,OAAQ,EAAE,CACjC,CAEA,SAAS1C,EACP,EACA,EACA,EACA,EACkB,CAClB,MAAO,CACL,OAAQC,EAAS,OACjB,OACA,MACA,GAAIJ,IAAc,IAAA,IAAaA,IAAc,GAAK,CAAC,EAAI,CAAE,WAAU,CACrE,CACF,CAYA,SAASsB,EACP,EACA,EACA,EACA,EACA,EACM,CACN,IAAMwB,EAAkB7C,EAAkBF,EAAY,WAAW,GAAK,GAChEgD,EAASpC,EAAKqC,UACpB,GAAI,OAAOD,GAAW,UAAYA,IAAW,IAAMA,IAAWD,EAAiB,OAC/E,IAAMG,EAAUF,GAAmC,MAAQA,IAAW,GAChE7C,EAA4B,CAChC,GAAGC,EAAgBC,EAAUC,EAAMV,CAAG,EACtC,UAAWmD,CACb,EACA,MAAMG,EACF,IAAIvD,EAAc,qBAAsB,CAAC,EAAGQ,CAAO,EACnD,IAAIR,EAAc,sBAAuB,CAAC,EAAGQ,CAAO,CAC1D,CAEA,SAASI,EACP,EACA,EACA,EACA,EACe,CAEf,GAAIF,EAAS,SAAA,IACX,OAAO,IAAIV,EACT,kBACA,CAAE,OAAQU,EAAS,MAAO,EAC1BD,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,CAChD,EAEF,IAAMkD,EAAS1C,EAASH,CAAI,EACtB8C,EAASC,EAAkB/C,EAAM,OAAO,EACxCgD,EACJpD,EAAkBiD,EAAQ,MAAM,GAChCjD,EAAkBkD,EAAQ,MAAM,GAChClD,EAAkBkD,EAAQ,UAAU,GACpC,aAGIG,EAAU5C,EAAoBL,CAAI,EAClCkD,EAAenD,EAAS,SAAW,IAAMoD,EAAepD,CAAQ,EAAI,IAAA,GAQ1E,OAPIiD,IAAS,aACJ,IAAI3D,EACT,aACA,CAAE,OAAQU,EAAS,OAAQ,MAAK,cAAekD,CAAQ,EACvDnD,EAAgBC,EAAUC,EAAMV,EAAKK,CAAS,CAChD,EAEKN,EAAc,kBACnB2D,EACAC,EACAlD,EAAS,OACTC,EACAV,EACA4D,EACAvD,IAAc,GAAK,IAAA,GAAYA,CACjC,CACF,CAEA,SAASQ,EAAS,EAAqD,CACrE,OAAO,OAAOqC,GAAU,UAAYA,EAC/BA,EACD,IAAA,EACN,CAEA,SAASxB,EAAc,EAAiC,CACtD,OAAO,OAAOwB,GAAU,UAAY,OAAO,UAAUA,CAAK,GAAKA,GAAS,CAC1E"}
@@ -1,2 +1,2 @@
1
- import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{GSWAP_ENVIRONMENTS as n}from"../types/env.js";import{debugLog as r}from"../utils/debug.js";import{ReconnectionBackoff as i}from"../utils/reconnection.js";const a=`gdex.jsonrpc.v1`,o=[`add`,`remove`,`collect`];function s(e){let{pool:t}=e;return(e.version===`v1`||e.version===`v2`)&&typeof t==`object`&&!!t&&typeof e.poolHash==`string`&&typeof e.transactionId==`string`&&o.includes(e.action)&&typeof e.owner==`string`&&typeof e.amount0==`string`&&typeof e.amount1==`string`&&typeof e.blockNumber==`number`&&typeof e.timestamp==`string`}var c=class extends Error{constructor(t,n,r){super(n),e(this,`code`,void 0),e(this,`data`,void 0),this.name=`GdexStreamError`,this.code=t,r!==void 0&&(this.data=r)}};function l(e){let t=typeof e==`object`&&e?e.subscriptionId:void 0;if(typeof t!=`string`)throw new c(-32603,`GDEX subscribe response is missing its subscriptionId`);return t}var u=class{constructor(r={}){e(this,`url`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`apiKey`,void 0),e(this,`webSocketConstructor`,void 0),e(this,`backoff`,void 0),e(this,`socket`,void 0),e(this,`connectPromise`,void 0),e(this,`nextRequestId`,0),e(this,`pending`,/* @__PURE__ */ new Map),e(this,`subscriptionsByServerId`,/* @__PURE__ */ new Map),e(this,`activeSubscriptions`,/* @__PURE__ */ new Set),e(this,`intentionalClose`,!1),e(this,`reconnecting`,!1),e(this,`reconnectTimer`,void 0),e(this,`reconnectDelayResolve`,void 0),this.url=r.url??n.prod.dexBackendWsUrl,this.requestTimeoutMs=r.requestTimeoutMs??15e3,this.backoff=new i({maxAttempts:r.reconnectAttempts??5,baseDelayMs:r.reconnectDelayMs??2e3});let a=r.webSocketImpl??globalThis.WebSocket;if(typeof a!=`function`)throw new t(`STREAM_WEBSOCKET_UNAVAILABLE`,{});if(this.webSocketConstructor=a,r.apiKey!==void 0){if(r.apiKey===``||r.webSocketImpl===void 0)throw new t(`STREAM_API_KEY_UNUSABLE`,{});this.apiKey=r.apiKey}}connect(){return this.isConnected()?Promise.resolve():(this.connectPromise||(this.intentionalClose=!1,this.clearReconnectTimer(),this.connectPromise=this.openSocket()),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.reconnecting=!1,this.clearReconnectTimer(),this.rejectPending(new t(`STREAM_DISCONNECTED`,{}));let e=this.socket;this.socket=void 0,this.connectPromise=void 0,e?.close(1e3,`client disconnect`)}isConnected(){return this.socket?.readyState===1}request(e,t){return this.send(e,t)}send(e,n,r){if(!this.isConnected()||!this.socket)return Promise.reject(new t(`STREAM_NOT_CONNECTED`,{}));let i=++this.nextRequestId,a={jsonrpc:`2.0`,id:i,method:e};return n!==void 0&&(a.params=n),new Promise((n,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(new t(`STREAM_REQUEST_TIMEOUT`,{method:e,timeoutMs:this.requestTimeoutMs}))},this.requestTimeoutMs);this.pending.set(i,{resolve:e=>n(e),reject:o,timeout:s,onResult:r});try{this.socket?.send(JSON.stringify(a))}catch(e){clearTimeout(s),this.pending.delete(i),o(e instanceof Error?e:Error(String(e)))}})}serverInfo(){return this.request(`gdex_serverInfo`)}ping(){return this.request(`gdex_ping`)}getPool(e){return this.request(`gdex_getPool`,e)}getBalance(e,t){return this.request(`gdex_getBalance`,t===void 0?{owner:e}:{owner:e,tokenClassKey:t})}getPositions(e){return this.request(`gdex_getPositions`,e)}getBlockHeight(){return this.request(`gdex_getBlockHeight`)}quote(e){return this.request(`gdex_quote`,e)}getToken(e){return this.request(`gdex_getToken`,{tokenClassKey:e})}subscribeSwaps(e,t={}){return this.subscribe(`swap`,e,t)}subscribePool(e,t,n={}){return this.subscribe(`pool`,t,{...e,...n})}subscribeBalances(e,t,n={}){return this.subscribe(`balance`,t,{owner:e,...n})}subscribePoolCreated(e,t={}){return this.subscribe(`poolCreated`,e,t)}subscribeLiquidity(e,t={}){return this.subscribe(`liquidity`,t=>{s(t)?e(t):r(`Ignoring a malformed liquidity event from the GDEX stream`)},t)}subscribeBlocks(e,t={}){return this.subscribe(`blocks`,e,t)}openSocket(){return new Promise((e,n)=>{let i=!1,o=this.apiKey===void 0?new this.webSocketConstructor(this.url,a):new this.webSocketConstructor(this.url,a,{headers:{"x-api-key":this.apiKey}});this.socket=o,o.onopen=()=>{this.socket===o&&(i=!0,this.connectPromise=void 0,this.reconnecting||this.backoff.reset(),r(`Connected to GDEX stream`),e())},o.onmessage=e=>this.handleMessage(e.data),o.onerror=()=>{i||n(new t(`STREAM_CONNECT_FAILED`,{url:this.url}))},o.onclose=e=>{this.socket===o&&(this.socket=void 0,this.connectPromise=void 0,i||n(new t(`STREAM_CLOSED_BEFORE_CONNECT`,{closeCode:e.code??0})),this.rejectPending(new t(`STREAM_CONNECTION_CLOSED`,{closeCode:e.code??0})),!this.intentionalClose&&!this.reconnecting&&this.startReconnectLoop())}})}handleMessage(e){if(typeof e!=`string`){r(`Ignoring non-text GDEX WebSocket frame`);return}let t;try{t=JSON.parse(e)}catch{r(`Ignoring invalid JSON from GDEX stream`);return}if(typeof t.id==`number`){let e=this.pending.get(t.id);if(!e)return;if(clearTimeout(e.timeout),this.pending.delete(t.id),t.error){let n=typeof t.error.code==`number`?t.error.code:-32603,r=typeof t.error.message==`string`?t.error.message:`GDEX request failed`;e.reject(new c(n,r,t.error.data))}else{try{e.onResult?.(t.result)}catch(t){e.reject(t instanceof Error?t:Error(String(t)));return}e.resolve(t.result)}return}if(t.method!==`gdex_subscription`||!this.isRecord(t.params))return;let n=t.params.subscription,i=t.params.result;if(typeof n!=`string`||!this.isRecord(i))return;let a=this.subscriptionsByServerId.get(n);if(a?.active)try{a.callback(i)}catch(e){r(`GDEX subscription callback failed`,e)}}async subscribe(e,t,n){let r={channel:e,...n},i={subscriptionId:``,unsubscribe:async()=>this.unsubscribe(a)},a={serverId:``,params:r,callback:t,handle:i,active:!0};return await this.send(`gdex_subscribe`,r,e=>{let t=l(e);a.serverId=t,i.subscriptionId=t,this.activeSubscriptions.add(a),this.subscriptionsByServerId.set(t,a)}),i}async unsubscribe(e){e.active&&(e.active=!1,this.activeSubscriptions.delete(e),this.subscriptionsByServerId.delete(e.serverId),this.isConnected()&&await this.request(`gdex_unsubscribe`,{subscriptionId:e.serverId}))}startReconnectLoop(){this.reconnecting||this.intentionalClose||(this.reconnecting=!0,this.reconnectLoop())}async reconnectLoop(){for(;!this.intentionalClose&&this.backoff.shouldRetry();){let e=this.backoff.nextDelayMs();if(this.backoff.recordAttempt(),r(`GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${e}ms`),await this.waitForReconnectDelay(e),this.intentionalClose)break;try{await this.openSocket(),await this.resubscribeAll(),this.backoff.reset(),this.reconnecting=!1;return}catch(e){r(`GDEX reconnect failed: ${e instanceof Error?e.message:String(e)}`)}}this.reconnecting=!1,this.intentionalClose||r(`GDEX reconnection attempts exhausted`)}async resubscribeAll(){this.subscriptionsByServerId.clear();for(let e of this.activeSubscriptions){if(!e.active)continue;let t={...e.params,snapshot:!0},n=await this.resubscribeWithRateLimitRetry(t,t=>{let n=l(t);e.active&&(e.serverId=n,e.handle.subscriptionId=n,this.subscriptionsByServerId.set(n,e))});e.active||await this.request(`gdex_unsubscribe`,{subscriptionId:n.subscriptionId})}}async resubscribeWithRateLimitRetry(e,t){for(let n=0;;n++)try{return await this.send(`gdex_subscribe`,e,t)}catch(e){if(!(e instanceof c)||e.code!==-32003||n>=5)throw e;let t=this.readRetryAfterMs(e.data);r(`GDEX resubscribe rate limited; retrying in ${t}ms`),await new Promise(e=>setTimeout(e,t))}}waitForReconnectDelay(e){return new Promise(t=>{this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.reconnectDelayResolve=void 0,t()},e),this.reconnectDelayResolve=t})}clearReconnectTimer(){this.reconnectTimer!==void 0&&clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0;let e=this.reconnectDelayResolve;this.reconnectDelayResolve=void 0,e?.()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timeout),t.reject(e);this.pending.clear()}readRetryAfterMs(e){return!this.isRecord(e)||typeof e.retryAfterMs!=`number`||e.retryAfterMs<0?1e3:e.retryAfterMs}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}};export{c as GdexStreamError,u as GdexStreamService,s as isGdexLiquidityEvent};
1
+ import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{userRef as n}from"../utils/validation.js";import{GSWAP_ENVIRONMENTS as r}from"../types/env.js";import{debugLog as i}from"../utils/debug.js";import{ReconnectionBackoff as a}from"../utils/reconnection.js";const o=`gdex.jsonrpc.v1`,s=[`add`,`remove`,`collect`];function c(e){let{pool:t}=e;return(e.version===`v1`||e.version===`v2`)&&typeof t==`object`&&!!t&&typeof e.poolHash==`string`&&typeof e.transactionId==`string`&&s.includes(e.action)&&typeof e.owner==`string`&&typeof e.amount0==`string`&&typeof e.amount1==`string`&&typeof e.blockNumber==`number`&&typeof e.timestamp==`string`}var l=class extends Error{constructor(t,n,r){super(n),e(this,`code`,void 0),e(this,`data`,void 0),this.name=`GdexStreamError`,this.code=t,r!==void 0&&(this.data=r)}};function u(e){let t=typeof e==`object`&&e?e.subscriptionId:void 0;if(typeof t!=`string`)throw new l(-32603,`GDEX subscribe response is missing its subscriptionId`);return t}var d=class{constructor(n={}){e(this,`url`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`apiKey`,void 0),e(this,`webSocketConstructor`,void 0),e(this,`backoff`,void 0),e(this,`socket`,void 0),e(this,`connectPromise`,void 0),e(this,`nextRequestId`,0),e(this,`pending`,/* @__PURE__ */ new Map),e(this,`subscriptionsByServerId`,/* @__PURE__ */ new Map),e(this,`activeSubscriptions`,/* @__PURE__ */ new Set),e(this,`intentionalClose`,!1),e(this,`reconnecting`,!1),e(this,`reconnectTimer`,void 0),e(this,`reconnectDelayResolve`,void 0),this.url=n.url??r.prod.dexBackendWsUrl,this.requestTimeoutMs=n.requestTimeoutMs??15e3,this.backoff=new a({maxAttempts:n.reconnectAttempts??5,baseDelayMs:n.reconnectDelayMs??2e3});let i=n.webSocketImpl??globalThis.WebSocket;if(typeof i!=`function`)throw new t(`STREAM_WEBSOCKET_UNAVAILABLE`,{});if(this.webSocketConstructor=i,n.apiKey!==void 0){if(n.apiKey===``||n.webSocketImpl===void 0)throw new t(`STREAM_API_KEY_UNUSABLE`,{});this.apiKey=n.apiKey}}connect(){return this.isConnected()?Promise.resolve():(this.connectPromise||(this.intentionalClose=!1,this.clearReconnectTimer(),this.connectPromise=this.openSocket()),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.reconnecting=!1,this.clearReconnectTimer(),this.rejectPending(new t(`STREAM_DISCONNECTED`,{}));let e=this.socket;this.socket=void 0,this.connectPromise=void 0,e?.close(1e3,`client disconnect`)}isConnected(){return this.socket?.readyState===1}request(e,t){return this.send(e,t)}send(e,n,r){if(!this.isConnected()||!this.socket)return Promise.reject(new t(`STREAM_NOT_CONNECTED`,{}));let i=++this.nextRequestId,a={jsonrpc:`2.0`,id:i,method:e};return n!==void 0&&(a.params=n),new Promise((n,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(new t(`STREAM_REQUEST_TIMEOUT`,{method:e,timeoutMs:this.requestTimeoutMs}))},this.requestTimeoutMs);this.pending.set(i,{resolve:e=>n(e),reject:o,timeout:s,onResult:r});try{this.socket?.send(JSON.stringify(a))}catch(e){clearTimeout(s),this.pending.delete(i),o(e instanceof Error?e:Error(String(e)))}})}serverInfo(){return this.request(`gdex_serverInfo`)}ping(){return this.request(`gdex_ping`)}getPool(e){return this.request(`gdex_getPool`,e)}async getBalance(e,t){let r=n(e,`owner`);return this.request(`gdex_getBalance`,t===void 0?{owner:r}:{owner:r,tokenClassKey:t})}async getPositions(e){return this.request(`gdex_getPositions`,{...e,owner:n(e.owner,`owner`)})}getBlockHeight(){return this.request(`gdex_getBlockHeight`)}quote(e){return this.request(`gdex_quote`,e)}getToken(e){return this.request(`gdex_getToken`,{tokenClassKey:e})}subscribeSwaps(e,t={}){return this.subscribe(`swap`,e,t)}subscribePool(e,t,n={}){return this.subscribe(`pool`,t,{...e,...n})}async subscribeBalances(e,t,r={}){return this.subscribe(`balance`,t,{owner:n(e,`owner`),...r})}subscribePoolCreated(e,t={}){return this.subscribe(`poolCreated`,e,t)}async subscribeLiquidity(e,t={}){let r=t.owner===void 0?t:{...t,owner:n(t.owner,`owner`)};return this.subscribe(`liquidity`,t=>{c(t)?e(t):i(`Ignoring a malformed liquidity event from the GDEX stream`)},r)}subscribeBlocks(e,t={}){return this.subscribe(`blocks`,e,t)}openSocket(){return new Promise((e,n)=>{let r=!1,a=this.apiKey===void 0?new this.webSocketConstructor(this.url,o):new this.webSocketConstructor(this.url,o,{headers:{"x-api-key":this.apiKey}});this.socket=a,a.onopen=()=>{this.socket===a&&(r=!0,this.connectPromise=void 0,this.reconnecting||this.backoff.reset(),i(`Connected to GDEX stream`),e())},a.onmessage=e=>this.handleMessage(e.data),a.onerror=()=>{r||n(new t(`STREAM_CONNECT_FAILED`,{url:this.url}))},a.onclose=e=>{this.socket===a&&(this.socket=void 0,this.connectPromise=void 0,r||n(new t(`STREAM_CLOSED_BEFORE_CONNECT`,{closeCode:e.code??0})),this.rejectPending(new t(`STREAM_CONNECTION_CLOSED`,{closeCode:e.code??0})),!this.intentionalClose&&!this.reconnecting&&this.startReconnectLoop())}})}handleMessage(e){if(typeof e!=`string`){i(`Ignoring non-text GDEX WebSocket frame`);return}let t;try{t=JSON.parse(e)}catch{i(`Ignoring invalid JSON from GDEX stream`);return}if(typeof t.id==`number`){let e=this.pending.get(t.id);if(!e)return;if(clearTimeout(e.timeout),this.pending.delete(t.id),t.error){let n=typeof t.error.code==`number`?t.error.code:-32603,r=typeof t.error.message==`string`?t.error.message:`GDEX request failed`;e.reject(new l(n,r,t.error.data))}else{try{e.onResult?.(t.result)}catch(t){e.reject(t instanceof Error?t:Error(String(t)));return}e.resolve(t.result)}return}if(t.method!==`gdex_subscription`||!this.isRecord(t.params))return;let n=t.params.subscription,r=t.params.result;if(typeof n!=`string`||!this.isRecord(r))return;let a=this.subscriptionsByServerId.get(n);if(a?.active)try{a.callback(r)}catch(e){i(`GDEX subscription callback failed`,e)}}async subscribe(e,t,n){let r={channel:e,...n},i={subscriptionId:``,unsubscribe:async()=>this.unsubscribe(a)},a={serverId:``,params:r,callback:t,handle:i,active:!0};return await this.send(`gdex_subscribe`,r,e=>{let t=u(e);a.serverId=t,i.subscriptionId=t,this.activeSubscriptions.add(a),this.subscriptionsByServerId.set(t,a)}),i}async unsubscribe(e){e.active&&(e.active=!1,this.activeSubscriptions.delete(e),this.subscriptionsByServerId.delete(e.serverId),this.isConnected()&&await this.request(`gdex_unsubscribe`,{subscriptionId:e.serverId}))}startReconnectLoop(){this.reconnecting||this.intentionalClose||(this.reconnecting=!0,this.reconnectLoop())}async reconnectLoop(){for(;!this.intentionalClose&&this.backoff.shouldRetry();){let e=this.backoff.nextDelayMs();if(this.backoff.recordAttempt(),i(`GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${e}ms`),await this.waitForReconnectDelay(e),this.intentionalClose)break;try{await this.openSocket(),await this.resubscribeAll(),this.backoff.reset(),this.reconnecting=!1;return}catch(e){i(`GDEX reconnect failed: ${e instanceof Error?e.message:String(e)}`)}}this.reconnecting=!1,this.intentionalClose||i(`GDEX reconnection attempts exhausted`)}async resubscribeAll(){this.subscriptionsByServerId.clear();for(let e of this.activeSubscriptions){if(!e.active)continue;let t={...e.params,snapshot:!0},n=await this.resubscribeWithRateLimitRetry(t,t=>{let n=u(t);e.active&&(e.serverId=n,e.handle.subscriptionId=n,this.subscriptionsByServerId.set(n,e))});e.active||await this.request(`gdex_unsubscribe`,{subscriptionId:n.subscriptionId})}}async resubscribeWithRateLimitRetry(e,t){for(let n=0;;n++)try{return await this.send(`gdex_subscribe`,e,t)}catch(e){if(!(e instanceof l)||e.code!==-32003||n>=5)throw e;let t=this.readRetryAfterMs(e.data);i(`GDEX resubscribe rate limited; retrying in ${t}ms`),await new Promise(e=>setTimeout(e,t))}}waitForReconnectDelay(e){return new Promise(t=>{this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.reconnectDelayResolve=void 0,t()},e),this.reconnectDelayResolve=t})}clearReconnectTimer(){this.reconnectTimer!==void 0&&clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0;let e=this.reconnectDelayResolve;this.reconnectDelayResolve=void 0,e?.()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timeout),t.reject(e);this.pending.clear()}readRetryAfterMs(e){return!this.isRecord(e)||typeof e.retryAfterMs!=`number`||e.retryAfterMs<0?1e3:e.retryAfterMs}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}};export{l as GdexStreamError,d as GdexStreamService,c as isGdexLiquidityEvent};
2
2
  //# sourceMappingURL=gdex_stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gdex_stream.js","names":["_defineProperty","GDEX_SUBPROTOCOL","LIQUIDITY_ACTIONS","isGdexLiquidityEvent","value","\"version\"","pool","\"poolHash\"","\"transactionId\"","\"action\"","\"owner\"","\"amount0\"","\"amount1\"","\"blockNumber\"","\"timestamp\"","GdexStreamError","message","code","data","readSubscriptionId","id","GdexStreamService","config","GSWAP_ENVIRONMENTS","ReconnectionBackoff","implementation","GSwapSDKError","socket","method","params","frame","\"params\"","timeout","reject","resolve","error","selector","tokenClassKey","opts","cb","event","debugLog","opened","pending","errorMessage","subscriptionId","\"subscription\"","result","\"result\"","subscription","options","handle","serverId","delay","attempt","onResult","retryAfterMs","\"retryAfterMs\""],"sources":["../../../src/classes/gdex_stream.ts"],"sourcesContent":["import { GSWAP_ENVIRONMENTS } from '../types/env.js';\nimport { debugLog } from '../utils/debug.js';\nimport { ReconnectionBackoff } from '../utils/reconnection.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nconst GDEX_SUBPROTOCOL = 'gdex.jsonrpc.v1';\nconst RATE_LIMITED = -32003;\nconst MAX_RESUBSCRIBE_RATE_RETRIES = 5;\nconst WEBSOCKET_OPEN = 1;\n\n/** Options for {@link GdexStreamService}. */\nexport interface GdexStreamConfig {\n /** Stream endpoint. Defaults to production (`wss://dex-backend-prod1.defi.gala.com/ws`). */\n url?: string | undefined;\n /** Reconnect attempts after an unexpected close. Default 5. */\n reconnectAttempts?: number | undefined;\n /** Delay before the first reconnect attempt; doubles each attempt. Default 2000 ms. */\n reconnectDelayMs?: number | undefined;\n /** How long a request waits for its response. Default 15000 ms. */\n requestTimeoutMs?: number | undefined;\n /**\n * A standards-compatible WebSocket constructor. Required on Node.js older than 22, which has no\n * global `WebSocket` (pass the one from the `ws` package).\n */\n webSocketImpl?: unknown;\n /**\n * Presents `x-api-key` on the WebSocket upgrade request, which defi-backend uses to serve the\n * PRIVILEGED view (shadow swaps with the wallet unredacted). Without it, or with a wrong key, the\n * connection is simply public: the server never says whether a privileged mode exists.\n *\n * It must travel as an HTTP header, because the server reads no other credential, and a browser\n * `WebSocket` cannot set headers. So this option needs a constructor that accepts them as its\n * third argument (`{ headers }`): the `ws` package on Node.js, or React Native's built-in\n * `WebSocket`. It therefore REQUIRES `webSocketImpl` (the platform default is never assumed to\n * honor headers, and a key that is silently dropped would look like a working privileged\n * connection); the constructor throws otherwise. Use it from server-side code only: a key\n * shipped inside a browser or app bundle is not a secret. Browser clients stay public.\n */\n apiKey?: string | undefined;\n}\n\n/** The channels of the realtime stream. */\nexport type GdexChannel = 'pool' | 'balance' | 'poolCreated' | 'swap' | 'liquidity' | 'blocks';\n\n/** A pool named by its two token class keys (pipe form) and fee tier. */\nexport interface GdexPoolKey {\n token0ClassKey: string;\n token1ClassKey: string;\n fee: number;\n}\n\n/** A pool named either by its key or by its hash (`v2:<poolRef>` for a v2 pool). */\nexport type GdexPoolSelector = { pool: GdexPoolKey } | { poolHash: string };\n\n/** Options common to every subscription. */\nexport interface GdexSubscribeOptions {\n /** Send the current state right after the subscribe response. */\n snapshot?: boolean | undefined;\n /** Trim each event to these fields; identity and envelope fields always stay. */\n fields?: string[] | undefined;\n}\n\n/** Filters for {@link GdexStreamService.subscribeLiquidity}; all optional. */\nexport interface GdexLiquidityFilter {\n /** Only this pool, named by its key. */\n pool?: GdexPoolKey | undefined;\n /** Only this pool, named by its hash (`v2:<poolRef>` for a v2 pool). */\n poolHash?: string | undefined;\n /** Only events for this LP wallet (the position's owner). */\n owner?: string | undefined;\n /** Only this transaction. */\n transactionId?: string | undefined;\n /** Contract version filter. */\n version?: 'v1' | 'v2' | 'all' | undefined;\n}\n\n/** One committed add, remove or collect, as the `liquidity` channel reports it. */\nexport interface GdexLiquidityEvent {\n version: 'v1' | 'v2';\n pool: GdexPoolKey;\n poolHash: string;\n transactionId: string;\n /** `add`, `remove` or `collect`. */\n action: 'add' | 'remove' | 'collect';\n /** The position's owner (the LP wallet). */\n owner: string;\n /** v1: the position id. v2: the chain position key `<pool>|<tickLow>|<tickHigh>|<owner>`. */\n positionId?: string;\n tickLower?: number;\n tickUpper?: number;\n /** v2 only: the position's liquidity after the operation; `\"0\"` means it is closed. */\n liquidityAfter?: string;\n /** Principal moved: deposited by an add, withdrawn by a remove, `\"0\"` for a collect. */\n amount0: string;\n amount1: string;\n /** Fees paid out. v2: always present (`\"0\"` for an add). v1: present on a collect only. */\n fees0?: string;\n fees1?: string;\n /** v2 only. */\n token0Symbol?: string;\n token1Symbol?: string;\n blockNumber: number;\n timestamp: string;\n}\n\nconst LIQUIDITY_ACTIONS: readonly unknown[] = ['add', 'remove', 'collect'];\n\n/** Whether a stream payload carries every field of a {@link GdexLiquidityEvent}. */\nexport function isGdexLiquidityEvent(\n value: Record<string, unknown>,\n): value is Record<string, unknown> & GdexLiquidityEvent {\n const { pool } = value;\n return (\n (value['version'] === 'v1' || value['version'] === 'v2') &&\n typeof pool === 'object' &&\n pool !== null &&\n typeof value['poolHash'] === 'string' &&\n typeof value['transactionId'] === 'string' &&\n LIQUIDITY_ACTIONS.includes(value['action']) &&\n typeof value['owner'] === 'string' &&\n typeof value['amount0'] === 'string' &&\n typeof value['amount1'] === 'string' &&\n typeof value['blockNumber'] === 'number' &&\n typeof value['timestamp'] === 'string'\n );\n}\n\n/** A live subscription. */\nexport interface GdexSubscription {\n subscriptionId: string;\n unsubscribe(): Promise<void>;\n}\n\n/** A JSON-RPC error answered by the stream. */\nexport class GdexStreamError extends Error {\n /** The JSON-RPC error code. */\n readonly code: number;\n /** The error's optional `data` member, as the server sent it. */\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = 'GdexStreamError';\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\ninterface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code?: number; reason?: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\ninterface WebSocketConstructor {\n new (\n url: string,\n protocols?: string | string[],\n options?: { headers: Record<string, string> },\n ): WebSocketLike;\n}\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: Error): void;\n timeout: ReturnType<typeof setTimeout>;\n /**\n * Runs SYNCHRONOUSLY when the response frame is handled, before any frame that follows it in\n * the same read. Subscriptions register here: the server writes a snapshot right after the\n * subscribe response, and a runtime that delivers both frames without yielding to microtasks\n * (Node's `ws` does, for frames in one chunk) would otherwise drop the snapshot because the\n * awaiting caller has not registered the subscription yet.\n */\n onResult?: ((value: unknown) => void) | undefined;\n}\n\ntype EventCallback = (event: Record<string, unknown>) => void;\n\ninterface ActiveSubscription {\n serverId: string;\n readonly params: Record<string, unknown>;\n readonly callback: EventCallback;\n readonly handle: MutableGdexSubscription;\n active: boolean;\n}\n\ninterface MutableGdexSubscription extends GdexSubscription {\n subscriptionId: string;\n}\n\nfunction readSubscriptionId(value: unknown): string {\n const id =\n typeof value === 'object' && value !== null\n ? (value as { subscriptionId?: unknown }).subscriptionId\n : undefined;\n if (typeof id !== 'string') {\n throw new GdexStreamError(-32603, 'GDEX subscribe response is missing its subscriptionId');\n }\n return id;\n}\n\ninterface JsonRpcResponse {\n id?: unknown;\n method?: unknown;\n result?: unknown;\n error?: { code?: unknown; message?: unknown; data?: unknown };\n params?: unknown;\n}\n\n/**\n * Client for the gSwap realtime stream (gdex WebSocket Protocol v1): JSON-RPC 2.0 over one raw\n * WebSocket, with automatic reconnect and resubscribe.\n *\n * @example\n * ```typescript\n * const stream = new GdexStreamService();\n * await stream.connect();\n * await stream.subscribeLiquidity(event => console.log(event.action, event.owner), {\n * owner: 'client|618ae395c1c653111d3315be',\n * });\n * ```\n */\nexport class GdexStreamService {\n private readonly url: string;\n private readonly requestTimeoutMs: number;\n private readonly apiKey: string | undefined;\n private readonly webSocketConstructor: WebSocketConstructor;\n private readonly backoff: ReconnectionBackoff;\n private socket: WebSocketLike | undefined;\n private connectPromise: Promise<void> | undefined;\n private nextRequestId = 0;\n private readonly pending = new Map<number, PendingRequest>();\n private readonly subscriptionsByServerId = new Map<string, ActiveSubscription>();\n private readonly activeSubscriptions = new Set<ActiveSubscription>();\n private intentionalClose = false;\n private reconnecting = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n private reconnectDelayResolve: (() => void) | undefined;\n\n constructor(config: GdexStreamConfig = {}) {\n this.url = config.url ?? GSWAP_ENVIRONMENTS.prod.dexBackendWsUrl;\n this.requestTimeoutMs = config.requestTimeoutMs ?? 15_000;\n this.backoff = new ReconnectionBackoff({\n maxAttempts: config.reconnectAttempts ?? 5,\n baseDelayMs: config.reconnectDelayMs ?? 2_000,\n });\n\n const implementation =\n config.webSocketImpl ?? (globalThis as { WebSocket?: unknown }).WebSocket;\n if (typeof implementation !== 'function') {\n throw new GSwapSDKError('STREAM_WEBSOCKET_UNAVAILABLE', {});\n }\n this.webSocketConstructor = implementation as WebSocketConstructor;\n if (config.apiKey !== undefined) {\n if (config.apiKey === '' || config.webSocketImpl === undefined) {\n throw new GSwapSDKError('STREAM_API_KEY_UNUSABLE', {});\n }\n this.apiKey = config.apiKey;\n }\n }\n\n /** Open the connection. Resolves at once when already connected. */\n connect(): Promise<void> {\n if (this.isConnected()) return Promise.resolve();\n if (this.connectPromise) return this.connectPromise;\n this.intentionalClose = false;\n this.clearReconnectTimer();\n this.connectPromise = this.openSocket();\n return this.connectPromise;\n }\n\n /** Close the connection and stop reconnecting. */\n disconnect(): void {\n this.intentionalClose = true;\n this.reconnecting = false;\n this.clearReconnectTimer();\n this.rejectPending(new GSwapSDKError('STREAM_DISCONNECTED', {}));\n const socket = this.socket;\n this.socket = undefined;\n this.connectPromise = undefined;\n socket?.close(1000, 'client disconnect');\n }\n\n /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */\n isConnected(): boolean {\n return this.socket?.readyState === WEBSOCKET_OPEN;\n }\n\n /** Raw JSON-RPC escape hatch. */\n request<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {\n return this.send<T>(method, params);\n }\n\n private send<T>(\n method: string,\n params: Record<string, unknown> | undefined,\n onResult?: (value: unknown) => void,\n ): Promise<T> {\n if (!this.isConnected() || !this.socket) {\n return Promise.reject(new GSwapSDKError('STREAM_NOT_CONNECTED', {}));\n }\n\n const id = ++this.nextRequestId;\n const frame: Record<string, unknown> = { jsonrpc: '2.0', id, method };\n if (params !== undefined) frame['params'] = params;\n\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(id);\n reject(\n new GSwapSDKError('STREAM_REQUEST_TIMEOUT', { method, timeoutMs: this.requestTimeoutMs }),\n );\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve: (value) => resolve(value as T), reject, timeout, onResult });\n\n try {\n this.socket?.send(JSON.stringify(frame));\n } catch (error) {\n clearTimeout(timeout);\n this.pending.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */\n serverInfo(): Promise<Record<string, unknown>> {\n return this.request('gdex_serverInfo');\n }\n\n /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */\n ping(): Promise<{ pong: boolean; serverTime: string }> {\n return this.request('gdex_ping');\n }\n\n /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */\n getPool(selector: GdexPoolSelector): Promise<Record<string, unknown>> {\n return this.request('gdex_getPool', selector);\n }\n\n /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */\n getBalance(owner: string, tokenClassKey?: string): Promise<Record<string, unknown>> {\n return this.request(\n 'gdex_getBalance',\n tokenClassKey === undefined ? { owner } : { owner, tokenClassKey },\n );\n }\n\n /**\n * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the\n * returned `bookmark` back in as `bookmark` for the next page.\n */\n getPositions(opts: {\n owner: string;\n pool?: GdexPoolKey;\n poolHash?: string;\n limit?: number;\n bookmark?: string;\n }): Promise<{ positions: Record<string, unknown>[]; bookmark: string }> {\n return this.request('gdex_getPositions', opts);\n }\n\n /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */\n getBlockHeight(): Promise<{ blockNumber: number; timestamp: string }> {\n return this.request('gdex_getBlockHeight');\n }\n\n /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */\n quote(params: {\n tokenIn: string;\n tokenOut: string;\n fee?: number;\n amountIn?: string;\n amountOut?: string;\n }): Promise<Record<string, unknown>> {\n return this.request('gdex_quote', params);\n }\n\n /** `gdex_getToken`: the server's record of one token class, as it sends it. */\n getToken(tokenClassKey: string): Promise<Record<string, unknown>> {\n return this.request('gdex_getToken', { tokenClassKey });\n }\n\n /** One event per committed swap. Omit the pool to receive every pool's swaps. */\n subscribeSwaps(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & {\n pool?: GdexPoolKey;\n poolHash?: string;\n transactionId?: string;\n } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('swap', cb, opts);\n }\n\n /**\n * State changes of one pool (price, tick, reserves, liquidity). These events carry no acting wallet:\n * on v2 `creator` is whoever created the pool, not whoever just traded or added liquidity. For\n * \"who did it\", use {@link subscribeLiquidity} (`owner`) or {@link subscribeSwaps} (`sender`).\n */\n subscribePool(\n selector: GdexPoolSelector,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('pool', cb, { ...selector, ...opts });\n }\n\n /** Balance changes of one wallet. */\n subscribeBalances(\n owner: string,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('balance', cb, { owner, ...opts });\n }\n\n /** Each newly created pool. */\n subscribePoolCreated(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('poolCreated', cb, opts);\n }\n\n /**\n * One event per committed AddLiquidity, RemoveLiquidity and CollectPositionFees, on both contract\n * versions. Every filter is optional; with none, every liquidity event arrives. These events never\n * appear on {@link subscribeSwaps}. There is no snapshot: read positions with {@link getPositions}.\n * Deduplicate by `transactionId` plus `positionId`: a v1 BatchSubmit can hold several operations\n * under one transaction id.\n */\n subscribeLiquidity(\n cb: (event: GdexLiquidityEvent) => void,\n opts: GdexSubscribeOptions & GdexLiquidityFilter = {},\n ): Promise<GdexSubscription> {\n return this.subscribe(\n 'liquidity',\n (event) => {\n if (isGdexLiquidityEvent(event)) cb(event);\n else debugLog('Ignoring a malformed liquidity event from the GDEX stream');\n },\n opts,\n );\n }\n\n /** Each block-height advance. */\n subscribeBlocks(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('blocks', cb, opts);\n }\n\n private openSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let opened = false;\n const socket =\n this.apiKey === undefined\n ? new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL)\n : new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL, {\n headers: { 'x-api-key': this.apiKey },\n });\n this.socket = socket;\n\n socket.onopen = () => {\n if (this.socket !== socket) return;\n opened = true;\n this.connectPromise = undefined;\n if (!this.reconnecting) this.backoff.reset();\n debugLog('Connected to GDEX stream');\n resolve();\n };\n socket.onmessage = (event) => this.handleMessage(event.data);\n socket.onerror = () => {\n if (!opened) reject(new GSwapSDKError('STREAM_CONNECT_FAILED', { url: this.url }));\n };\n socket.onclose = (event) => {\n if (this.socket !== socket) return;\n this.socket = undefined;\n this.connectPromise = undefined;\n if (!opened) {\n reject(new GSwapSDKError('STREAM_CLOSED_BEFORE_CONNECT', { closeCode: event.code ?? 0 }));\n }\n this.rejectPending(\n new GSwapSDKError('STREAM_CONNECTION_CLOSED', { closeCode: event.code ?? 0 }),\n );\n if (!this.intentionalClose && !this.reconnecting) this.startReconnectLoop();\n };\n });\n }\n\n private handleMessage(data: unknown): void {\n if (typeof data !== 'string') {\n debugLog('Ignoring non-text GDEX WebSocket frame');\n return;\n }\n\n let message: JsonRpcResponse;\n try {\n message = JSON.parse(data) as JsonRpcResponse;\n } catch {\n debugLog('Ignoring invalid JSON from GDEX stream');\n return;\n }\n\n if (typeof message.id === 'number') {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timeout);\n this.pending.delete(message.id);\n if (message.error) {\n const code = typeof message.error.code === 'number' ? message.error.code : -32603;\n const errorMessage =\n typeof message.error.message === 'string' ? message.error.message : 'GDEX request failed';\n pending.reject(new GdexStreamError(code, errorMessage, message.error.data));\n } else {\n try {\n pending.onResult?.(message.result);\n } catch (error) {\n pending.reject(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n pending.resolve(message.result);\n }\n return;\n }\n\n if (message.method !== 'gdex_subscription' || !this.isRecord(message.params)) return;\n const subscriptionId = message.params['subscription'];\n const result = message.params['result'];\n if (typeof subscriptionId !== 'string' || !this.isRecord(result)) return;\n const subscription = this.subscriptionsByServerId.get(subscriptionId);\n if (!subscription?.active) return;\n try {\n subscription.callback(result);\n } catch (error) {\n debugLog('GDEX subscription callback failed', error);\n }\n }\n\n private async subscribe(\n channel: GdexChannel,\n callback: EventCallback,\n options: object,\n ): Promise<GdexSubscription> {\n const params: Record<string, unknown> = { channel, ...options };\n const handle: MutableGdexSubscription = {\n subscriptionId: '',\n unsubscribe: async () => this.unsubscribe(subscription),\n };\n const subscription: ActiveSubscription = {\n serverId: '',\n params,\n callback,\n handle,\n active: true,\n };\n // Registered inside the response handler, not after the await: see PendingRequest.onResult.\n await this.send('gdex_subscribe', params, (value) => {\n const serverId = readSubscriptionId(value);\n subscription.serverId = serverId;\n handle.subscriptionId = serverId;\n this.activeSubscriptions.add(subscription);\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n return handle;\n }\n\n private async unsubscribe(subscription: ActiveSubscription): Promise<void> {\n if (!subscription.active) return;\n subscription.active = false;\n this.activeSubscriptions.delete(subscription);\n this.subscriptionsByServerId.delete(subscription.serverId);\n if (this.isConnected()) {\n await this.request('gdex_unsubscribe', { subscriptionId: subscription.serverId });\n }\n }\n\n private startReconnectLoop(): void {\n if (this.reconnecting || this.intentionalClose) return;\n this.reconnecting = true;\n void this.reconnectLoop();\n }\n\n private async reconnectLoop(): Promise<void> {\n while (!this.intentionalClose && this.backoff.shouldRetry()) {\n const delay = this.backoff.nextDelayMs();\n this.backoff.recordAttempt();\n debugLog(\n `GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${delay}ms`,\n );\n await this.waitForReconnectDelay(delay);\n // `disconnect()` can run while the asynchronous delay is pending.\n if (this.intentionalClose) break;\n\n try {\n await this.openSocket();\n await this.resubscribeAll();\n this.backoff.reset();\n this.reconnecting = false;\n return;\n } catch (error) {\n debugLog(\n `GDEX reconnect failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n this.reconnecting = false;\n if (!this.intentionalClose) debugLog('GDEX reconnection attempts exhausted');\n }\n\n private async resubscribeAll(): Promise<void> {\n this.subscriptionsByServerId.clear();\n for (const subscription of this.activeSubscriptions) {\n if (!subscription.active) continue;\n const params = { ...subscription.params, snapshot: true };\n const result = await this.resubscribeWithRateLimitRetry(params, (value) => {\n const serverId = readSubscriptionId(value);\n // The consumer can unsubscribe while the asynchronous subscribe request is pending.\n if (!subscription.active) return;\n subscription.serverId = serverId;\n subscription.handle.subscriptionId = serverId;\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n if (!subscription.active) {\n await this.request('gdex_unsubscribe', { subscriptionId: result.subscriptionId });\n }\n }\n }\n\n private async resubscribeWithRateLimitRetry(\n params: Record<string, unknown>,\n onResult: (value: unknown) => void,\n ): Promise<{ subscriptionId: string }> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.send('gdex_subscribe', params, onResult);\n } catch (error) {\n if (\n !(error instanceof GdexStreamError) ||\n error.code !== RATE_LIMITED ||\n attempt >= MAX_RESUBSCRIBE_RATE_RETRIES\n ) {\n throw error;\n }\n const retryAfterMs = this.readRetryAfterMs(error.data);\n debugLog(`GDEX resubscribe rate limited; retrying in ${retryAfterMs}ms`);\n await new Promise<void>((resolve) => setTimeout(resolve, retryAfterMs));\n }\n }\n }\n\n private waitForReconnectDelay(delay: number): Promise<void> {\n return new Promise((resolve) => {\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = undefined;\n this.reconnectDelayResolve = undefined;\n resolve();\n }, delay);\n this.reconnectDelayResolve = resolve;\n });\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer !== undefined) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n const resolve = this.reconnectDelayResolve;\n this.reconnectDelayResolve = undefined;\n resolve?.();\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n private readRetryAfterMs(data: unknown): number {\n if (\n !this.isRecord(data) ||\n typeof data['retryAfterMs'] !== 'number' ||\n data['retryAfterMs'] < 0\n )\n return 1_000;\n return data['retryAfterMs'];\n }\n\n private isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gdex_stream.js","names":["_defineProperty","GDEX_SUBPROTOCOL","LIQUIDITY_ACTIONS","isGdexLiquidityEvent","value","\"version\"","pool","\"poolHash\"","\"transactionId\"","\"action\"","\"owner\"","\"amount0\"","\"amount1\"","\"blockNumber\"","\"timestamp\"","GdexStreamError","message","code","data","readSubscriptionId","id","GdexStreamService","config","GSWAP_ENVIRONMENTS","ReconnectionBackoff","implementation","GSwapSDKError","socket","method","params","frame","\"params\"","timeout","reject","resolve","error","selector","ref","userRef","owner","tokenClassKey","opts","cb","filter","event","debugLog","opened","pending","errorMessage","subscriptionId","\"subscription\"","result","\"result\"","subscription","options","handle","serverId","delay","attempt","onResult","retryAfterMs","\"retryAfterMs\""],"sources":["../../../src/classes/gdex_stream.ts"],"sourcesContent":["import { GSWAP_ENVIRONMENTS } from '../types/env.js';\nimport { debugLog } from '../utils/debug.js';\nimport { userRef } from '../utils/validation.js';\nimport { ReconnectionBackoff } from '../utils/reconnection.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nconst GDEX_SUBPROTOCOL = 'gdex.jsonrpc.v1';\nconst RATE_LIMITED = -32003;\nconst MAX_RESUBSCRIBE_RATE_RETRIES = 5;\nconst WEBSOCKET_OPEN = 1;\n\n/** Options for {@link GdexStreamService}. */\nexport interface GdexStreamConfig {\n /** Stream endpoint. Defaults to production (`wss://dex-backend-prod1.defi.gala.com/ws`). */\n url?: string | undefined;\n /** Reconnect attempts after an unexpected close. Default 5. */\n reconnectAttempts?: number | undefined;\n /** Delay before the first reconnect attempt; doubles each attempt. Default 2000 ms. */\n reconnectDelayMs?: number | undefined;\n /** How long a request waits for its response. Default 15000 ms. */\n requestTimeoutMs?: number | undefined;\n /**\n * A standards-compatible WebSocket constructor. Required on Node.js older than 22, which has no\n * global `WebSocket` (pass the one from the `ws` package).\n */\n webSocketImpl?: unknown;\n /**\n * Presents `x-api-key` on the WebSocket upgrade request, which defi-backend uses to serve the\n * PRIVILEGED view (shadow swaps with the wallet unredacted). Without it, or with a wrong key, the\n * connection is simply public: the server never says whether a privileged mode exists.\n *\n * It must travel as an HTTP header, because the server reads no other credential, and a browser\n * `WebSocket` cannot set headers. So this option needs a constructor that accepts them as its\n * third argument (`{ headers }`): the `ws` package on Node.js, or React Native's built-in\n * `WebSocket`. It therefore REQUIRES `webSocketImpl` (the platform default is never assumed to\n * honor headers, and a key that is silently dropped would look like a working privileged\n * connection); the constructor throws otherwise. Use it from server-side code only: a key\n * shipped inside a browser or app bundle is not a secret. Browser clients stay public.\n */\n apiKey?: string | undefined;\n}\n\n/** The channels of the realtime stream. */\nexport type GdexChannel = 'pool' | 'balance' | 'poolCreated' | 'swap' | 'liquidity' | 'blocks';\n\n/** A pool named by its two token class keys (pipe form) and fee tier. */\nexport interface GdexPoolKey {\n token0ClassKey: string;\n token1ClassKey: string;\n fee: number;\n}\n\n/** A pool named either by its key or by its hash (`v2:<poolRef>` for a v2 pool). */\nexport type GdexPoolSelector = { pool: GdexPoolKey } | { poolHash: string };\n\n/** Options common to every subscription. */\nexport interface GdexSubscribeOptions {\n /** Send the current state right after the subscribe response. */\n snapshot?: boolean | undefined;\n /** Trim each event to these fields; identity and envelope fields always stay. */\n fields?: string[] | undefined;\n}\n\n/** Filters for {@link GdexStreamService.subscribeLiquidity}; all optional. */\nexport interface GdexLiquidityFilter {\n /** Only this pool, named by its key. */\n pool?: GdexPoolKey | undefined;\n /** Only this pool, named by its hash (`v2:<poolRef>` for a v2 pool). */\n poolHash?: string | undefined;\n /** Only events for this LP wallet (the position's owner). */\n owner?: string | undefined;\n /** Only this transaction. */\n transactionId?: string | undefined;\n /** Contract version filter. */\n version?: 'v1' | 'v2' | 'all' | undefined;\n}\n\n/** One committed add, remove or collect, as the `liquidity` channel reports it. */\nexport interface GdexLiquidityEvent {\n version: 'v1' | 'v2';\n pool: GdexPoolKey;\n poolHash: string;\n transactionId: string;\n /** `add`, `remove` or `collect`. */\n action: 'add' | 'remove' | 'collect';\n /** The position's owner (the LP wallet). */\n owner: string;\n /** v1: the position id. v2: the chain position key `<pool>|<tickLow>|<tickHigh>|<owner>`. */\n positionId?: string;\n tickLower?: number;\n tickUpper?: number;\n /** v2 only: the position's liquidity after the operation; `\"0\"` means it is closed. */\n liquidityAfter?: string;\n /** Principal moved: deposited by an add, withdrawn by a remove, `\"0\"` for a collect. */\n amount0: string;\n amount1: string;\n /** Fees paid out. v2: always present (`\"0\"` for an add). v1: present on a collect only. */\n fees0?: string;\n fees1?: string;\n /** v2 only. */\n token0Symbol?: string;\n token1Symbol?: string;\n blockNumber: number;\n timestamp: string;\n}\n\nconst LIQUIDITY_ACTIONS: readonly unknown[] = ['add', 'remove', 'collect'];\n\n/** Whether a stream payload carries every field of a {@link GdexLiquidityEvent}. */\nexport function isGdexLiquidityEvent(\n value: Record<string, unknown>,\n): value is Record<string, unknown> & GdexLiquidityEvent {\n const { pool } = value;\n return (\n (value['version'] === 'v1' || value['version'] === 'v2') &&\n typeof pool === 'object' &&\n pool !== null &&\n typeof value['poolHash'] === 'string' &&\n typeof value['transactionId'] === 'string' &&\n LIQUIDITY_ACTIONS.includes(value['action']) &&\n typeof value['owner'] === 'string' &&\n typeof value['amount0'] === 'string' &&\n typeof value['amount1'] === 'string' &&\n typeof value['blockNumber'] === 'number' &&\n typeof value['timestamp'] === 'string'\n );\n}\n\n/** A live subscription. */\nexport interface GdexSubscription {\n subscriptionId: string;\n unsubscribe(): Promise<void>;\n}\n\n/** A JSON-RPC error answered by the stream. */\nexport class GdexStreamError extends Error {\n /** The JSON-RPC error code. */\n readonly code: number;\n /** The error's optional `data` member, as the server sent it. */\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = 'GdexStreamError';\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\ninterface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code?: number; reason?: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\ninterface WebSocketConstructor {\n new (\n url: string,\n protocols?: string | string[],\n options?: { headers: Record<string, string> },\n ): WebSocketLike;\n}\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: Error): void;\n timeout: ReturnType<typeof setTimeout>;\n /**\n * Runs SYNCHRONOUSLY when the response frame is handled, before any frame that follows it in\n * the same read. Subscriptions register here: the server writes a snapshot right after the\n * subscribe response, and a runtime that delivers both frames without yielding to microtasks\n * (Node's `ws` does, for frames in one chunk) would otherwise drop the snapshot because the\n * awaiting caller has not registered the subscription yet.\n */\n onResult?: ((value: unknown) => void) | undefined;\n}\n\ntype EventCallback = (event: Record<string, unknown>) => void;\n\ninterface ActiveSubscription {\n serverId: string;\n readonly params: Record<string, unknown>;\n readonly callback: EventCallback;\n readonly handle: MutableGdexSubscription;\n active: boolean;\n}\n\ninterface MutableGdexSubscription extends GdexSubscription {\n subscriptionId: string;\n}\n\nfunction readSubscriptionId(value: unknown): string {\n const id =\n typeof value === 'object' && value !== null\n ? (value as { subscriptionId?: unknown }).subscriptionId\n : undefined;\n if (typeof id !== 'string') {\n throw new GdexStreamError(-32603, 'GDEX subscribe response is missing its subscriptionId');\n }\n return id;\n}\n\ninterface JsonRpcResponse {\n id?: unknown;\n method?: unknown;\n result?: unknown;\n error?: { code?: unknown; message?: unknown; data?: unknown };\n params?: unknown;\n}\n\n/**\n * Client for the gSwap realtime stream (gdex WebSocket Protocol v1): JSON-RPC 2.0 over one raw\n * WebSocket, with automatic reconnect and resubscribe.\n *\n * @example\n * ```typescript\n * const stream = new GdexStreamService();\n * await stream.connect();\n * await stream.subscribeLiquidity(event => console.log(event.action, event.owner), {\n * owner: 'client|618ae395c1c653111d3315be',\n * });\n * ```\n */\nexport class GdexStreamService {\n private readonly url: string;\n private readonly requestTimeoutMs: number;\n private readonly apiKey: string | undefined;\n private readonly webSocketConstructor: WebSocketConstructor;\n private readonly backoff: ReconnectionBackoff;\n private socket: WebSocketLike | undefined;\n private connectPromise: Promise<void> | undefined;\n private nextRequestId = 0;\n private readonly pending = new Map<number, PendingRequest>();\n private readonly subscriptionsByServerId = new Map<string, ActiveSubscription>();\n private readonly activeSubscriptions = new Set<ActiveSubscription>();\n private intentionalClose = false;\n private reconnecting = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n private reconnectDelayResolve: (() => void) | undefined;\n\n constructor(config: GdexStreamConfig = {}) {\n this.url = config.url ?? GSWAP_ENVIRONMENTS.prod.dexBackendWsUrl;\n this.requestTimeoutMs = config.requestTimeoutMs ?? 15_000;\n this.backoff = new ReconnectionBackoff({\n maxAttempts: config.reconnectAttempts ?? 5,\n baseDelayMs: config.reconnectDelayMs ?? 2_000,\n });\n\n const implementation =\n config.webSocketImpl ?? (globalThis as { WebSocket?: unknown }).WebSocket;\n if (typeof implementation !== 'function') {\n throw new GSwapSDKError('STREAM_WEBSOCKET_UNAVAILABLE', {});\n }\n this.webSocketConstructor = implementation as WebSocketConstructor;\n if (config.apiKey !== undefined) {\n if (config.apiKey === '' || config.webSocketImpl === undefined) {\n throw new GSwapSDKError('STREAM_API_KEY_UNUSABLE', {});\n }\n this.apiKey = config.apiKey;\n }\n }\n\n /** Open the connection. Resolves at once when already connected. */\n connect(): Promise<void> {\n if (this.isConnected()) return Promise.resolve();\n if (this.connectPromise) return this.connectPromise;\n this.intentionalClose = false;\n this.clearReconnectTimer();\n this.connectPromise = this.openSocket();\n return this.connectPromise;\n }\n\n /** Close the connection and stop reconnecting. */\n disconnect(): void {\n this.intentionalClose = true;\n this.reconnecting = false;\n this.clearReconnectTimer();\n this.rejectPending(new GSwapSDKError('STREAM_DISCONNECTED', {}));\n const socket = this.socket;\n this.socket = undefined;\n this.connectPromise = undefined;\n socket?.close(1000, 'client disconnect');\n }\n\n /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */\n isConnected(): boolean {\n return this.socket?.readyState === WEBSOCKET_OPEN;\n }\n\n /** Raw JSON-RPC escape hatch. */\n request<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {\n return this.send<T>(method, params);\n }\n\n private send<T>(\n method: string,\n params: Record<string, unknown> | undefined,\n onResult?: (value: unknown) => void,\n ): Promise<T> {\n if (!this.isConnected() || !this.socket) {\n return Promise.reject(new GSwapSDKError('STREAM_NOT_CONNECTED', {}));\n }\n\n const id = ++this.nextRequestId;\n const frame: Record<string, unknown> = { jsonrpc: '2.0', id, method };\n if (params !== undefined) frame['params'] = params;\n\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(id);\n reject(\n new GSwapSDKError('STREAM_REQUEST_TIMEOUT', { method, timeoutMs: this.requestTimeoutMs }),\n );\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve: (value) => resolve(value as T), reject, timeout, onResult });\n\n try {\n this.socket?.send(JSON.stringify(frame));\n } catch (error) {\n clearTimeout(timeout);\n this.pending.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */\n serverInfo(): Promise<Record<string, unknown>> {\n return this.request('gdex_serverInfo');\n }\n\n /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */\n ping(): Promise<{ pong: boolean; serverTime: string }> {\n return this.request('gdex_ping');\n }\n\n /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */\n getPool(selector: GdexPoolSelector): Promise<Record<string, unknown>> {\n return this.request('gdex_getPool', selector);\n }\n\n /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */\n async getBalance(owner: string, tokenClassKey?: string): Promise<Record<string, unknown>> {\n const ref = userRef(owner, 'owner');\n return this.request(\n 'gdex_getBalance',\n tokenClassKey === undefined ? { owner: ref } : { owner: ref, tokenClassKey },\n );\n }\n\n /**\n * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the\n * returned `bookmark` back in as `bookmark` for the next page.\n */\n async getPositions(opts: {\n owner: string;\n pool?: GdexPoolKey;\n poolHash?: string;\n limit?: number;\n bookmark?: string;\n }): Promise<{ positions: Record<string, unknown>[]; bookmark: string }> {\n return this.request('gdex_getPositions', { ...opts, owner: userRef(opts.owner, 'owner') });\n }\n\n /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */\n getBlockHeight(): Promise<{ blockNumber: number; timestamp: string }> {\n return this.request('gdex_getBlockHeight');\n }\n\n /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */\n quote(params: {\n tokenIn: string;\n tokenOut: string;\n fee?: number;\n amountIn?: string;\n amountOut?: string;\n }): Promise<Record<string, unknown>> {\n return this.request('gdex_quote', params);\n }\n\n /** `gdex_getToken`: the server's record of one token class, as it sends it. */\n getToken(tokenClassKey: string): Promise<Record<string, unknown>> {\n return this.request('gdex_getToken', { tokenClassKey });\n }\n\n /** One event per committed swap. Omit the pool to receive every pool's swaps. */\n subscribeSwaps(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & {\n pool?: GdexPoolKey;\n poolHash?: string;\n transactionId?: string;\n } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('swap', cb, opts);\n }\n\n /**\n * State changes of one pool (price, tick, reserves, liquidity). These events carry no acting wallet:\n * on v2 `creator` is whoever created the pool, not whoever just traded or added liquidity. For\n * \"who did it\", use {@link subscribeLiquidity} (`owner`) or {@link subscribeSwaps} (`sender`).\n */\n subscribePool(\n selector: GdexPoolSelector,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('pool', cb, { ...selector, ...opts });\n }\n\n /** Balance changes of one wallet. */\n async subscribeBalances(\n owner: string,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('balance', cb, { owner: userRef(owner, 'owner'), ...opts });\n }\n\n /** Each newly created pool. */\n subscribePoolCreated(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('poolCreated', cb, opts);\n }\n\n /**\n * One event per committed AddLiquidity, RemoveLiquidity and CollectPositionFees, on both contract\n * versions. Every filter is optional; with none, every liquidity event arrives. These events never\n * appear on {@link subscribeSwaps}. There is no snapshot: read positions with {@link getPositions}.\n * Deduplicate by `transactionId` plus `positionId`: a v1 BatchSubmit can hold several operations\n * under one transaction id.\n */\n async subscribeLiquidity(\n cb: (event: GdexLiquidityEvent) => void,\n opts: GdexSubscribeOptions & GdexLiquidityFilter = {},\n ): Promise<GdexSubscription> {\n const filter =\n opts.owner === undefined ? opts : { ...opts, owner: userRef(opts.owner, 'owner') };\n return this.subscribe(\n 'liquidity',\n (event) => {\n if (isGdexLiquidityEvent(event)) cb(event);\n else debugLog('Ignoring a malformed liquidity event from the GDEX stream');\n },\n filter,\n );\n }\n\n /** Each block-height advance. */\n subscribeBlocks(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('blocks', cb, opts);\n }\n\n private openSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let opened = false;\n const socket =\n this.apiKey === undefined\n ? new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL)\n : new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL, {\n headers: { 'x-api-key': this.apiKey },\n });\n this.socket = socket;\n\n socket.onopen = () => {\n if (this.socket !== socket) return;\n opened = true;\n this.connectPromise = undefined;\n if (!this.reconnecting) this.backoff.reset();\n debugLog('Connected to GDEX stream');\n resolve();\n };\n socket.onmessage = (event) => this.handleMessage(event.data);\n socket.onerror = () => {\n if (!opened) reject(new GSwapSDKError('STREAM_CONNECT_FAILED', { url: this.url }));\n };\n socket.onclose = (event) => {\n if (this.socket !== socket) return;\n this.socket = undefined;\n this.connectPromise = undefined;\n if (!opened) {\n reject(new GSwapSDKError('STREAM_CLOSED_BEFORE_CONNECT', { closeCode: event.code ?? 0 }));\n }\n this.rejectPending(\n new GSwapSDKError('STREAM_CONNECTION_CLOSED', { closeCode: event.code ?? 0 }),\n );\n if (!this.intentionalClose && !this.reconnecting) this.startReconnectLoop();\n };\n });\n }\n\n private handleMessage(data: unknown): void {\n if (typeof data !== 'string') {\n debugLog('Ignoring non-text GDEX WebSocket frame');\n return;\n }\n\n let message: JsonRpcResponse;\n try {\n message = JSON.parse(data) as JsonRpcResponse;\n } catch {\n debugLog('Ignoring invalid JSON from GDEX stream');\n return;\n }\n\n if (typeof message.id === 'number') {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timeout);\n this.pending.delete(message.id);\n if (message.error) {\n const code = typeof message.error.code === 'number' ? message.error.code : -32603;\n const errorMessage =\n typeof message.error.message === 'string' ? message.error.message : 'GDEX request failed';\n pending.reject(new GdexStreamError(code, errorMessage, message.error.data));\n } else {\n try {\n pending.onResult?.(message.result);\n } catch (error) {\n pending.reject(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n pending.resolve(message.result);\n }\n return;\n }\n\n if (message.method !== 'gdex_subscription' || !this.isRecord(message.params)) return;\n const subscriptionId = message.params['subscription'];\n const result = message.params['result'];\n if (typeof subscriptionId !== 'string' || !this.isRecord(result)) return;\n const subscription = this.subscriptionsByServerId.get(subscriptionId);\n if (!subscription?.active) return;\n try {\n subscription.callback(result);\n } catch (error) {\n debugLog('GDEX subscription callback failed', error);\n }\n }\n\n private async subscribe(\n channel: GdexChannel,\n callback: EventCallback,\n options: object,\n ): Promise<GdexSubscription> {\n const params: Record<string, unknown> = { channel, ...options };\n const handle: MutableGdexSubscription = {\n subscriptionId: '',\n unsubscribe: async () => this.unsubscribe(subscription),\n };\n const subscription: ActiveSubscription = {\n serverId: '',\n params,\n callback,\n handle,\n active: true,\n };\n // Registered inside the response handler, not after the await: see PendingRequest.onResult.\n await this.send('gdex_subscribe', params, (value) => {\n const serverId = readSubscriptionId(value);\n subscription.serverId = serverId;\n handle.subscriptionId = serverId;\n this.activeSubscriptions.add(subscription);\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n return handle;\n }\n\n private async unsubscribe(subscription: ActiveSubscription): Promise<void> {\n if (!subscription.active) return;\n subscription.active = false;\n this.activeSubscriptions.delete(subscription);\n this.subscriptionsByServerId.delete(subscription.serverId);\n if (this.isConnected()) {\n await this.request('gdex_unsubscribe', { subscriptionId: subscription.serverId });\n }\n }\n\n private startReconnectLoop(): void {\n if (this.reconnecting || this.intentionalClose) return;\n this.reconnecting = true;\n void this.reconnectLoop();\n }\n\n private async reconnectLoop(): Promise<void> {\n while (!this.intentionalClose && this.backoff.shouldRetry()) {\n const delay = this.backoff.nextDelayMs();\n this.backoff.recordAttempt();\n debugLog(\n `GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${delay}ms`,\n );\n await this.waitForReconnectDelay(delay);\n // `disconnect()` can run while the asynchronous delay is pending.\n if (this.intentionalClose) break;\n\n try {\n await this.openSocket();\n await this.resubscribeAll();\n this.backoff.reset();\n this.reconnecting = false;\n return;\n } catch (error) {\n debugLog(\n `GDEX reconnect failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n this.reconnecting = false;\n if (!this.intentionalClose) debugLog('GDEX reconnection attempts exhausted');\n }\n\n private async resubscribeAll(): Promise<void> {\n this.subscriptionsByServerId.clear();\n for (const subscription of this.activeSubscriptions) {\n if (!subscription.active) continue;\n const params = { ...subscription.params, snapshot: true };\n const result = await this.resubscribeWithRateLimitRetry(params, (value) => {\n const serverId = readSubscriptionId(value);\n // The consumer can unsubscribe while the asynchronous subscribe request is pending.\n if (!subscription.active) return;\n subscription.serverId = serverId;\n subscription.handle.subscriptionId = serverId;\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n if (!subscription.active) {\n await this.request('gdex_unsubscribe', { subscriptionId: result.subscriptionId });\n }\n }\n }\n\n private async resubscribeWithRateLimitRetry(\n params: Record<string, unknown>,\n onResult: (value: unknown) => void,\n ): Promise<{ subscriptionId: string }> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.send('gdex_subscribe', params, onResult);\n } catch (error) {\n if (\n !(error instanceof GdexStreamError) ||\n error.code !== RATE_LIMITED ||\n attempt >= MAX_RESUBSCRIBE_RATE_RETRIES\n ) {\n throw error;\n }\n const retryAfterMs = this.readRetryAfterMs(error.data);\n debugLog(`GDEX resubscribe rate limited; retrying in ${retryAfterMs}ms`);\n await new Promise<void>((resolve) => setTimeout(resolve, retryAfterMs));\n }\n }\n }\n\n private waitForReconnectDelay(delay: number): Promise<void> {\n return new Promise((resolve) => {\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = undefined;\n this.reconnectDelayResolve = undefined;\n resolve();\n }, delay);\n this.reconnectDelayResolve = resolve;\n });\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer !== undefined) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n const resolve = this.reconnectDelayResolve;\n this.reconnectDelayResolve = undefined;\n resolve?.();\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n private readRetryAfterMs(data: unknown): number {\n if (\n !this.isRecord(data) ||\n typeof data['retryAfterMs'] !== 'number' ||\n data['retryAfterMs'] < 0\n )\n return 1_000;\n return data['retryAfterMs'];\n }\n\n private isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n"],"mappings":"8VAMA,MAAMC,EAAmB,kBAoGnBC,EAAwC,CAAC,MAAO,SAAU,SAAS,EAGzE,SAAgBC,EACd,EACuD,CACvD,GAAM,CAAE,QAASC,EACjB,OACGA,EAAMC,UAAe,MAAQD,EAAMC,UAAe,OACnD,OAAOC,GAAS,YAChBA,GACA,OAAOF,EAAMG,UAAgB,UAC7B,OAAOH,EAAMI,eAAqB,UAClCN,EAAkB,SAASE,EAAMK,MAAS,GAC1C,OAAOL,EAAMM,OAAa,UAC1B,OAAON,EAAMO,SAAe,UAC5B,OAAOP,EAAMQ,SAAe,UAC5B,OAAOR,EAAMS,aAAmB,UAChC,OAAOT,EAAMU,WAAiB,QAElC,CASA,IAAaC,EAAb,cAAqC,KAAM,CAMzC,YAAY,EAAc,EAAiB,EAAgB,CACzD,MAAMC,CAAO,EALNhB,EAAA,KAAA,OAAA,IAAA,EAAA,EAEAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAIP,KAAK,KAAO,kBACZ,KAAK,KAAOiB,EACRC,IAAS,IAAA,KAAW,KAAK,KAAOA,EACtC,CACF,EAgDA,SAASC,EAAmB,EAAwB,CAClD,IAAMC,EACJ,OAAOhB,GAAU,UAAYA,EACxBA,EAAuC,eACxC,IAAA,GACN,GAAI,OAAOgB,GAAO,SAChB,MAAM,IAAIL,EAAgB,OAAQ,uDAAuD,EAE3F,OAAOK,CACT,CAuBA,IAAaC,EAAb,KAA+B,CAiB7B,YAAY,EAA2B,CAAC,EAAG,CAhB1BrB,EAAA,KAAA,MAAA,IAAA,EAAA,EACAA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,SAAA,IAAA,EAAA,EACAA,EAAA,KAAA,uBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,UAAA,IAAA,EAAA,EACTA,EAAA,KAAA,SAAA,IAAA,EAAA,EACAA,EAAA,KAAA,iBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,gBAAgB,CAAA,EACPA,EAAA,KAAA,0BAAU,IAAI,GAA4B,EAC1CA,EAAA,KAAA,0CAA0B,IAAI,GAAgC,EAC9DA,EAAA,KAAA,sCAAsB,IAAI,GAAwB,EAC3DA,EAAA,KAAA,mBAAmB,EAAA,EACnBA,EAAA,KAAA,eAAe,EAAA,EACfA,EAAA,KAAA,iBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,wBAAA,IAAA,EAAA,EAGN,KAAK,IAAMsB,EAAO,KAAOC,EAAmB,KAAK,gBACjD,KAAK,iBAAmBD,EAAO,kBAAoB,KACnD,KAAK,QAAU,IAAIE,EAAoB,CACrC,YAAaF,EAAO,mBAAqB,EACzC,YAAaA,EAAO,kBAAoB,GAC1C,CAAC,EAED,IAAMG,EACJH,EAAO,eAAkB,WAAuC,UAClE,GAAI,OAAOG,GAAmB,WAC5B,MAAM,IAAIC,EAAc,+BAAgC,CAAC,CAAC,EAG5D,GADA,KAAK,qBAAuBD,EACxBH,EAAO,SAAW,IAAA,GAAW,CAC/B,GAAIA,EAAO,SAAW,IAAMA,EAAO,gBAAkB,IAAA,GACnD,MAAM,IAAII,EAAc,0BAA2B,CAAC,CAAC,EAEvD,KAAK,OAASJ,EAAO,MACvB,CACF,CAGA,SAAyB,CAMvB,OALI,KAAK,YAAY,EAAU,QAAQ,QAAQ,GAC3C,KAAK,iBACT,KAAK,iBAAmB,GACxB,KAAK,oBAAoB,EACzB,KAAK,eAAiB,KAAK,WAAW,GAC/B,KAAK,eACd,CAGA,YAAmB,CACjB,KAAK,iBAAmB,GACxB,KAAK,aAAe,GACpB,KAAK,oBAAoB,EACzB,KAAK,cAAc,IAAII,EAAc,sBAAuB,CAAC,CAAC,CAAC,EAC/D,IAAMC,EAAS,KAAK,OACpB,KAAK,OAAS,IAAA,GACd,KAAK,eAAiB,IAAA,GACtBA,GAAQ,MAAM,IAAM,mBAAmB,CACzC,CAGA,aAAuB,CACrB,OAAO,KAAK,QAAQ,aAAe,CACrC,CAGA,QAAqB,EAAgB,EAA8C,CACjF,OAAO,KAAK,KAAQC,EAAQC,CAAM,CACpC,CAEA,KACE,EACA,EACA,EACY,CACZ,GAAI,CAAC,KAAK,YAAY,GAAK,CAAC,KAAK,OAC/B,OAAO,QAAQ,OAAO,IAAIH,EAAc,uBAAwB,CAAC,CAAC,CAAC,EAGrE,IAAMN,EAAK,EAAE,KAAK,cACZU,EAAiC,CAAE,QAAS,MAAO,KAAI,QAAO,EAGpE,OAFID,IAAW,IAAA,KAAW,EAAME,OAAYF,GAErC,IAAI,SAAY,EAAS,IAAW,CACzC,IAAMG,EAAU,eAAiB,CAC/B,KAAK,QAAQ,OAAOZ,CAAE,EACtBa,EACE,IAAIP,EAAc,yBAA0B,CAAE,SAAQ,UAAW,KAAK,gBAAiB,CAAC,CAC1F,CACF,EAAG,KAAK,gBAAgB,EACxB,KAAK,QAAQ,IAAIN,EAAI,CAAE,QAAU,GAAUc,EAAQ9B,CAAU,EAAG,SAAQ,UAAS,UAAS,CAAC,EAE3F,GAAI,CACF,KAAK,QAAQ,KAAK,KAAK,UAAU0B,CAAK,CAAC,CACzC,OAASK,EAAO,CACd,aAAaH,CAAO,EACpB,KAAK,QAAQ,OAAOZ,CAAE,EACtBa,EAAOE,aAAiB,MAAQA,EAAY,MAAM,OAAOA,CAAK,CAAC,CAAC,CAClE,CACF,CAAC,CACH,CAGA,YAA+C,CAC7C,OAAO,KAAK,QAAQ,iBAAiB,CACvC,CAGA,MAAuD,CACrD,OAAO,KAAK,QAAQ,WAAW,CACjC,CAGA,QAAQ,EAA8D,CACpE,OAAO,KAAK,QAAQ,eAAgBC,CAAQ,CAC9C,CAGA,MAAM,WAAW,EAAe,EAA0D,CACxF,IAAMC,EAAMC,EAAQC,EAAO,OAAO,EAClC,OAAO,KAAK,QACV,kBACAC,IAAkB,IAAA,GAAY,CAAE,MAAOH,CAAI,EAAI,CAAE,MAAOA,EAAK,eAAc,CAC7E,CACF,CAMA,MAAM,aAAa,EAMqD,CACtE,OAAO,KAAK,QAAQ,oBAAqB,CAAE,GAAGI,EAAM,MAAOH,EAAQG,EAAK,MAAO,OAAO,CAAE,CAAC,CAC3F,CAGA,gBAAsE,CACpE,OAAO,KAAK,QAAQ,qBAAqB,CAC3C,CAGA,MAAM,EAM+B,CACnC,OAAO,KAAK,QAAQ,aAAcZ,CAAM,CAC1C,CAGA,SAAS,EAAyD,CAChE,OAAO,KAAK,QAAQ,gBAAiB,CAAE,eAAc,CAAC,CACxD,CAGA,eACE,EACA,EAII,CAAC,EACsB,CAC3B,OAAO,KAAK,UAAU,OAAQa,EAAID,CAAI,CACxC,CAOA,cACE,EACA,EACA,EAA6B,CAAC,EACH,CAC3B,OAAO,KAAK,UAAU,OAAQC,EAAI,CAAE,GAAGN,EAAU,GAAGK,CAAK,CAAC,CAC5D,CAGA,MAAM,kBACJ,EACA,EACA,EAA0D,CAAC,EAChC,CAC3B,OAAO,KAAK,UAAU,UAAWC,EAAI,CAAE,MAAOJ,EAAQC,EAAO,OAAO,EAAG,GAAGE,CAAK,CAAC,CAClF,CAGA,qBACE,EACA,EAA0D,CAAC,EAChC,CAC3B,OAAO,KAAK,UAAU,cAAeC,EAAID,CAAI,CAC/C,CASA,MAAM,mBACJ,EACA,EAAmD,CAAC,EACzB,CAC3B,IAAME,EACJF,EAAK,QAAU,IAAA,GAAYA,EAAO,CAAE,GAAGA,EAAM,MAAOH,EAAQG,EAAK,MAAO,OAAO,CAAE,EACnF,OAAO,KAAK,UACV,YACC,GAAU,CACLtC,EAAqByC,CAAK,EAAGF,EAAGE,CAAK,EACpCC,EAAS,2DAA2D,CAC3E,EACAF,CACF,CACF,CAGA,gBACE,EACA,EAA6B,CAAC,EACH,CAC3B,OAAO,KAAK,UAAU,SAAUD,EAAID,CAAI,CAC1C,CAEA,YAAoC,CAClC,OAAO,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAIK,EAAS,GACPnB,EACJ,KAAK,SAAW,IAAA,GACZ,IAAI,KAAK,qBAAqB,KAAK,IAAK1B,CAAgB,EACxD,IAAI,KAAK,qBAAqB,KAAK,IAAKA,EAAkB,CACxD,QAAS,CAAE,YAAa,KAAK,MAAO,CACtC,CAAC,EACP,KAAK,OAAS0B,EAEd,EAAO,WAAe,CAChB,KAAK,SAAWA,IACpB,EAAS,GACT,KAAK,eAAiB,IAAA,GACjB,KAAK,cAAc,KAAK,QAAQ,MAAM,EAC3CkB,EAAS,0BAA0B,EACnCX,EAAQ,EACV,EACA,EAAO,UAAa,GAAU,KAAK,cAAcU,EAAM,IAAI,EAC3D,EAAO,YAAgB,CAChBE,GAAQb,EAAO,IAAIP,EAAc,wBAAyB,CAAE,IAAK,KAAK,GAAI,CAAC,CAAC,CACnF,EACA,EAAO,QAAW,GAAU,CACtB,KAAK,SAAWC,IACpB,KAAK,OAAS,IAAA,GACd,KAAK,eAAiB,IAAA,GACjBmB,GACHb,EAAO,IAAIP,EAAc,+BAAgC,CAAE,UAAWkB,EAAM,MAAQ,CAAE,CAAC,CAAC,EAE1F,KAAK,cACH,IAAIlB,EAAc,2BAA4B,CAAE,UAAWkB,EAAM,MAAQ,CAAE,CAAC,CAC9E,EACI,CAAC,KAAK,kBAAoB,CAAC,KAAK,cAAc,KAAK,mBAAmB,EAC5E,CACF,CAAC,CACH,CAEA,cAAsB,EAAqB,CACzC,GAAI,OAAO1B,GAAS,SAAU,CAC5B2B,EAAS,wCAAwC,EACjD,MACF,CAEA,IAAI7B,EACJ,GAAI,CACF,EAAU,KAAK,MAAME,CAAI,CAC3B,MAAQ,CACN2B,EAAS,wCAAwC,EACjD,MACF,CAEA,GAAI,OAAO7B,EAAQ,IAAO,SAAU,CAClC,IAAM+B,EAAU,KAAK,QAAQ,IAAI/B,EAAQ,EAAE,EAC3C,GAAI,CAAC+B,EAAS,OAGd,GAFA,aAAaA,EAAQ,OAAO,EAC5B,KAAK,QAAQ,OAAO/B,EAAQ,EAAE,EAC1BA,EAAQ,MAAO,CACjB,IAAMC,EAAO,OAAOD,EAAQ,MAAM,MAAS,SAAWA,EAAQ,MAAM,KAAO,OACrEgC,EACJ,OAAOhC,EAAQ,MAAM,SAAY,SAAWA,EAAQ,MAAM,QAAU,sBACtE+B,EAAQ,OAAO,IAAIhC,EAAgBE,EAAM+B,EAAchC,EAAQ,MAAM,IAAI,CAAC,CAC5E,KAAO,CACL,GAAI,CACF+B,EAAQ,WAAW/B,EAAQ,MAAM,CACnC,OAASmB,EAAO,CACdY,EAAQ,OAAOZ,aAAiB,MAAQA,EAAY,MAAM,OAAOA,CAAK,CAAC,CAAC,EACxE,MACF,CACAY,EAAQ,QAAQ/B,EAAQ,MAAM,CAChC,CACA,MACF,CAEA,GAAIA,EAAQ,SAAW,qBAAuB,CAAC,KAAK,SAASA,EAAQ,MAAM,EAAG,OAC9E,IAAMiC,EAAiBjC,EAAQ,OAAOkC,aAChCC,EAASnC,EAAQ,OAAOoC,OAC9B,GAAI,OAAOH,GAAmB,UAAY,CAAC,KAAK,SAASE,CAAM,EAAG,OAClE,IAAME,EAAe,KAAK,wBAAwB,IAAIJ,CAAc,EACpE,GAAKI,GAAc,OACnB,GAAI,CACFA,EAAa,SAASF,CAAM,CAC9B,OAAShB,EAAO,CACdU,EAAS,oCAAqCV,CAAK,CACrD,CACF,CAEA,MAAc,UACZ,EACA,EACA,EAC2B,CAC3B,IAAMN,EAAkC,CAAE,UAAS,GAAGyB,CAAQ,EACxDC,EAAkC,CACtC,eAAgB,GAChB,YAAa,SAAY,KAAK,YAAYF,CAAY,CACxD,EACMA,EAAmC,CACvC,SAAU,GACV,SACA,WACA,SACA,OAAQ,EACV,EASA,OAPA,MAAM,KAAK,KAAK,iBAAkBxB,EAAS,GAAU,CACnD,IAAM2B,EAAWrC,EAAmBf,CAAK,EACzC,EAAa,SAAWoD,EACxB,EAAO,eAAiBA,EACxB,KAAK,oBAAoB,IAAIH,CAAY,EACzC,KAAK,wBAAwB,IAAIG,EAAUH,CAAY,CACzD,CAAC,EACME,CACT,CAEA,MAAc,YAAY,EAAiD,CACpEF,EAAa,SAClB,EAAa,OAAS,GACtB,KAAK,oBAAoB,OAAOA,CAAY,EAC5C,KAAK,wBAAwB,OAAOA,EAAa,QAAQ,EACrD,KAAK,YAAY,GACnB,MAAM,KAAK,QAAQ,mBAAoB,CAAE,eAAgBA,EAAa,QAAS,CAAC,EAEpF,CAEA,oBAAmC,CAC7B,KAAK,cAAgB,KAAK,mBAC9B,KAAK,aAAe,GACpB,KAAU,cAAc,EAC1B,CAEA,MAAc,eAA+B,CAC3C,KAAO,CAAC,KAAK,kBAAoB,KAAK,QAAQ,YAAY,GAAG,CAC3D,IAAMI,EAAQ,KAAK,QAAQ,YAAY,EAOvC,GANA,KAAK,QAAQ,cAAc,EAC3BZ,EACE,0BAA0B,KAAK,QAAQ,aAAa,GAAG,KAAK,QAAQ,YAAY,MAAMY,EAAM,GAC9F,EACA,MAAM,KAAK,sBAAsBA,CAAK,EAElC,KAAK,iBAAkB,MAE3B,GAAI,CACF,MAAM,KAAK,WAAW,EACtB,MAAM,KAAK,eAAe,EAC1B,KAAK,QAAQ,MAAM,EACnB,KAAK,aAAe,GACpB,MACF,OAAStB,EAAO,CACdU,EACE,0BAA0BV,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,GACjF,CACF,CACF,CACA,KAAK,aAAe,GACf,KAAK,kBAAkBU,EAAS,sCAAsC,CAC7E,CAEA,MAAc,gBAAgC,CAC5C,KAAK,wBAAwB,MAAM,EACnC,IAAK,IAAMQ,KAAgB,KAAK,oBAAqB,CACnD,GAAI,CAACA,EAAa,OAAQ,SAC1B,IAAMxB,EAAS,CAAE,GAAGwB,EAAa,OAAQ,SAAU,EAAK,EAClDF,EAAS,MAAM,KAAK,8BAA8BtB,EAAS,GAAU,CACzE,IAAM2B,EAAWrC,EAAmBf,CAAK,EAEpCiD,EAAa,SAClB,EAAa,SAAWG,EACxB,EAAa,OAAO,eAAiBA,EACrC,KAAK,wBAAwB,IAAIA,EAAUH,CAAY,EACzD,CAAC,EACIA,EAAa,QAChB,MAAM,KAAK,QAAQ,mBAAoB,CAAE,eAAgBF,EAAO,cAAe,CAAC,CAEpF,CACF,CAEA,MAAc,8BACZ,EACA,EACqC,CACrC,IAAK,IAAIO,EAAU,GAAK,IACtB,GAAI,CACF,OAAO,MAAM,KAAK,KAAK,iBAAkB7B,EAAQ8B,CAAQ,CAC3D,OAASxB,EAAO,CACd,GACE,EAAEA,aAAiBpB,IACnBoB,EAAM,OAAS,QACfuB,GAAW,EAEX,MAAMvB,EAER,IAAMyB,EAAe,KAAK,iBAAiBzB,EAAM,IAAI,EACrDU,EAAS,8CAA8Ce,EAAa,GAAG,EACvE,MAAM,IAAI,QAAe,GAAY,WAAW1B,EAAS0B,CAAY,CAAC,CACxE,CAEJ,CAEA,sBAA8B,EAA8B,CAC1D,OAAO,IAAI,QAAS,GAAY,CAC9B,KAAK,eAAiB,eAAiB,CACrC,KAAK,eAAiB,IAAA,GACtB,KAAK,sBAAwB,IAAA,GAC7B1B,EAAQ,CACV,EAAGuB,CAAK,EACR,KAAK,sBAAwBvB,CAC/B,CAAC,CACH,CAEA,qBAAoC,CAC9B,KAAK,iBAAmB,IAAA,IAAW,aAAa,KAAK,cAAc,EACvE,KAAK,eAAiB,IAAA,GACtB,IAAMA,EAAU,KAAK,sBACrB,KAAK,sBAAwB,IAAA,GAC7BA,IAAU,CACZ,CAEA,cAAsB,EAAoB,CACxC,IAAK,IAAMa,KAAW,KAAK,QAAQ,OAAO,EACxC,aAAaA,EAAQ,OAAO,EAC5BA,EAAQ,OAAOZ,CAAK,EAEtB,KAAK,QAAQ,MAAM,CACrB,CAEA,iBAAyB,EAAuB,CAO9C,MALE,CAAC,KAAK,SAASjB,CAAI,GACnB,OAAOA,EAAK2C,cAAoB,UAChC3C,EAAK2C,aAAkB,EAEhB,IACF3C,EAAK2C,YACd,CAEA,SAAiB,EAAkD,CACjE,OAAO,OAAOzD,GAAU,YAAYA,GAAkB,CAAC,MAAM,QAAQA,CAAK,CAC5E,CACF"}
@@ -1,2 +1,2 @@
1
- import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{Assets as t}from"./assets.js";import{DexFees as n}from"./dex_fees.js";import{ChainGateway as r}from"./gateway.js";import{GSWAP_ENVIRONMENTS as i}from"../types/env.js";import{GdexStreamService as a}from"./gdex_stream.js";import{HttpClient as o}from"./http_client.js";import{Leaderboard as s}from"./leaderboard.js";import{Market as c}from"./market.js";import{CanonicalSymbols as l,Symbols as u}from"./symbols.js";import{Pools as d}from"./pools.js";import{Positions as f}from"./positions.js";import{Quoting as p}from"./quoting.js";import{Swaps as m}from"./swaps.js";var h=class{constructor(a){e(this,`dexBackendBaseUrl`,void 0),e(this,`chainCallTimeoutMs`,void 0),e(this,`signer`,void 0),e(this,`walletAddress`,void 0),e(this,`gateway`,void 0),e(this,`symbols`,void 0),e(this,`quoting`,void 0),e(this,`pools`,void 0),e(this,`positions`,void 0),e(this,`swaps`,void 0),e(this,`assets`,void 0),e(this,`market`,void 0),e(this,`leaderboard`,void 0),e(this,`fees`,void 0),e(this,`dexBackendWsUrl`,void 0),e(this,`webSocketImpl`,void 0),e(this,`streamApiKey`,void 0),e(this,`streamClient`,void 0);let h=i[a?.env??`prod`];this.dexBackendBaseUrl=g(a?.dexBackendBaseUrl??h.dexBackendBaseUrl),this.chainCallTimeoutMs=a?.chainCallTimeoutMs??3e4,this.signer=a?.signer,this.walletAddress=a?.walletAddress;let _=new o(a?.httpRequestor,this.chainCallTimeoutMs,a?.wire);this.gateway=new r({dexBackendBaseUrl:this.dexBackendBaseUrl,chainCallTimeoutMs:this.chainCallTimeoutMs,...a?.wire===void 0?{}:{wire:a.wire},...a?.httpRequestor===void 0?{}:{httpRequestor:a.httpRequestor},...this.walletAddress===void 0?{}:{walletAddress:this.walletAddress}});let v={onInvalidEntry:a?.onInvalidEntry};this.symbols=new u(this.gateway,v);let y=a?.symbolResolution===`canonical`?new l:this.symbols;this.quoting=new p(this.gateway,y),this.pools=new d(this.gateway,y,v);let b={uniqueKeyPrefix:a?.uniqueKeyPrefix,...v};this.positions=new f(this.gateway,y,this.signer,this.walletAddress,b),this.swaps=new m(this.gateway,y,this.signer,this.walletAddress,b),this.assets=new t(this.dexBackendBaseUrl,_),this.market=new c(this.dexBackendBaseUrl,_,v),this.leaderboard=new s(this.dexBackendBaseUrl,_,v),this.fees=new n(this.gateway,this.signer),this.dexBackendWsUrl=a?.dexBackendWsUrl??(a?.dexBackendBaseUrl===void 0?h.dexBackendWsUrl:`${this.dexBackendBaseUrl.replace(/^http/u,`ws`)}/ws`),this.webSocketImpl=a?.webSocketImpl,this.streamApiKey=a?.streamApiKey}get stream(){return this.streamClient??(this.streamClient=new a({url:this.dexBackendWsUrl,...this.webSocketImpl===void 0?{}:{webSocketImpl:this.webSocketImpl},...this.streamApiKey===void 0?{}:{apiKey:this.streamApiKey}})),this.streamClient}};function g(e){return e.replace(/\/$/u,``)}export{h as GSwap};
1
+ import e from"../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/defineProperty.js";import{userRef as t}from"../utils/validation.js";import{Assets as n}from"./assets.js";import{DexFees as r}from"./dex_fees.js";import{ChainGateway as i}from"./gateway.js";import{GSWAP_ENVIRONMENTS as a}from"../types/env.js";import{GdexStreamService as o}from"./gdex_stream.js";import{HttpClient as s}from"./http_client.js";import{Leaderboard as c}from"./leaderboard.js";import{Market as l}from"./market.js";import{Onramper as u}from"./onramper.js";import{CanonicalSymbols as d,Symbols as f}from"./symbols.js";import{Pools as p}from"./pools.js";import{Positions as m}from"./positions.js";import{Quoting as h}from"./quoting.js";import{Swaps as g}from"./swaps.js";var _=class{constructor(o){e(this,`dexBackendBaseUrl`,void 0),e(this,`chainCallTimeoutMs`,void 0),e(this,`signer`,void 0),e(this,`walletAddress`,void 0),e(this,`gateway`,void 0),e(this,`symbols`,void 0),e(this,`quoting`,void 0),e(this,`pools`,void 0),e(this,`positions`,void 0),e(this,`swaps`,void 0),e(this,`assets`,void 0),e(this,`market`,void 0),e(this,`leaderboard`,void 0),e(this,`onramper`,void 0),e(this,`fees`,void 0),e(this,`dexBackendWsUrl`,void 0),e(this,`webSocketImpl`,void 0),e(this,`streamApiKey`,void 0),e(this,`streamClient`,void 0);let _=a[o?.env??`prod`];this.dexBackendBaseUrl=v(o?.dexBackendBaseUrl??_.dexBackendBaseUrl),this.chainCallTimeoutMs=o?.chainCallTimeoutMs??3e4,this.signer=o?.signer,this.walletAddress=o?.walletAddress===void 0?void 0:t(o.walletAddress,`walletAddress`);let y=new s(o?.httpRequestor,this.chainCallTimeoutMs,o?.wire);this.gateway=new i({dexBackendBaseUrl:this.dexBackendBaseUrl,chainCallTimeoutMs:this.chainCallTimeoutMs,...o?.wire===void 0?{}:{wire:o.wire},...o?.httpRequestor===void 0?{}:{httpRequestor:o.httpRequestor},...this.walletAddress===void 0?{}:{walletAddress:this.walletAddress}});let b={onInvalidEntry:o?.onInvalidEntry};this.symbols=new f(this.gateway,b);let x=o?.symbolResolution===`canonical`?new d:this.symbols;this.quoting=new h(this.gateway,x),this.pools=new p(this.gateway,x,b);let S={uniqueKeyPrefix:o?.uniqueKeyPrefix,...b};this.positions=new m(this.gateway,x,this.signer,this.walletAddress,S),this.swaps=new g(this.gateway,x,this.signer,this.walletAddress,S),this.assets=new n(this.dexBackendBaseUrl,y),this.market=new l(this.dexBackendBaseUrl,y,b),this.leaderboard=new c(this.dexBackendBaseUrl,y,b),this.onramper=new u(this.dexBackendBaseUrl,y),this.fees=new r(this.gateway,this.signer),this.dexBackendWsUrl=o?.dexBackendWsUrl??(o?.dexBackendBaseUrl===void 0?_.dexBackendWsUrl:`${this.dexBackendBaseUrl.replace(/^http/u,`ws`)}/ws`),this.webSocketImpl=o?.webSocketImpl,this.streamApiKey=o?.streamApiKey}get stream(){return this.streamClient??(this.streamClient=new o({url:this.dexBackendWsUrl,...this.webSocketImpl===void 0?{}:{webSocketImpl:this.webSocketImpl},...this.streamApiKey===void 0?{}:{apiKey:this.streamApiKey}})),this.streamClient}};function v(e){return e.replace(/\/$/u,``)}export{_ as GSwap};
2
2
  //# sourceMappingURL=gswap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gswap.js","names":["_defineProperty","GSwap","environment","GSWAP_ENVIRONMENTS","options","trimTrailingSlash","httpClient","HttpClient","ChainGateway","lenient","Symbols","resolver","CanonicalSymbols","Quoting","Pools","keyOptions","Positions","Swaps","Assets","Market","Leaderboard","DexFees","GdexStreamService","value"],"sources":["../../../src/classes/gswap.ts"],"sourcesContent":["import { Assets } from './assets.js';\nimport { DexFees } from './dex_fees.js';\nimport { ChainGateway } from './gateway.js';\nimport { GdexStreamService } from './gdex_stream.js';\nimport { HttpClient } from './http_client.js';\nimport { Leaderboard } from './leaderboard.js';\nimport { Market } from './market.js';\nimport { Pools } from './pools.js';\nimport { Positions } from './positions.js';\nimport { Quoting } from './quoting.js';\nimport type { GalaChainSigner, HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { CanonicalSymbols, Symbols } from './symbols.js';\nimport type { InvalidEntryHandler } from '../utils/lenient.js';\nimport { Swaps } from './swaps.js';\nimport type { GSwapEnv } from '../types/env.js';\nimport { GSWAP_ENVIRONMENTS } from '../types/env.js';\n\n/** Options for constructing a backend-routed SDK client. */\nexport interface GSwapOptions {\n /** Signs every write. Without one, reads work and any write throws `NO_SIGNER`. */\n signer?: GalaChainSigner | undefined;\n /**\n * The selected account, sent as `X-Wallet-Address` on writes (attribution only; the chain\n * recovers the signer from the signature). Required for shadow writes.\n */\n walletAddress?: string | undefined;\n /** `'stage'` or `'prod'` swap backend preset; defaults to `'prod'`. */\n env?: GSwapEnv | undefined;\n /** Overrides the preset's swap backend base URL (a test or private deployment). */\n dexBackendBaseUrl?: string | undefined;\n /** HTTP transport for every request; defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000); `Infinity` arms no timer. */\n chainCallTimeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the read requests (see {@link WireOptions}). */\n wire?: WireOptions | undefined;\n /**\n * How tokens are turned into trading symbols. `'registry'` (default) reads the symbol registry\n * once (`GET /v2/trade/symbols`, cached) and accepts symbols or class keys. `'canonical'` makes\n * no registry request: the caller passes the backend's canonical trading symbols (from a quote,\n * an estimate or a position), reads send tokens and ticks exactly as given (composite keys\n * included) and the backend orients the pair; see {@link CanonicalSymbols}.\n */\n symbolResolution?: 'registry' | 'canonical' | undefined;\n /**\n * Told about every row of a pool, symbol, position, price, price-series, season or leaderboard\n * answer that was skipped as unusable (see {@link InvalidEntryHandler}); without it such rows are\n * skipped silently.\n */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n /** Realtime stream endpoint. Defaults to the environment's, or is derived from `dexBackendBaseUrl`. */\n dexBackendWsUrl?: string | undefined;\n /** WebSocket constructor for the realtime stream; required on Node.js older than 22. */\n webSocketImpl?: unknown;\n /**\n * `x-api-key` for the privileged stream view; server-side only, and it requires `webSocketImpl`\n * (see `GdexStreamConfig.apiKey`).\n */\n streamApiKey?: string | undefined;\n /**\n * Prefix of every write's `uniqueKey` (`<prefix><uuid>`). Defaults to `galaswap-operation-`,\n * what frontend_v2 and wallet_extension send; defi-backend does not depend on it.\n */\n uniqueKeyPrefix?: string | undefined;\n}\n\n/**\n * Main entry point for the current GalaChainDex SDK: one client bundling the services that read\n * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,\n * `market`, `leaderboard`, `symbols`, `fees`, `stream`). See {@link GSwapOptions} for\n * configuration.\n */\nexport class GSwap {\n /** The swap backend base URL every request goes to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */\n public readonly chainCallTimeoutMs: number;\n /** The signer given at construction, if any. */\n public readonly signer: GalaChainSigner | undefined;\n /** The account given at construction, if any. */\n public readonly walletAddress: string | undefined;\n /** The chain-gateway client every other service reads and writes through. */\n public readonly gateway: ChainGateway;\n /** The trading-symbol registry. */\n public readonly symbols: Symbols;\n /** Read-only exact-input and exact-output quotes. */\n public readonly quoting: Quoting;\n /** Pool, slot0 and composite-pool reads. */\n public readonly pools: Pools;\n /** Position reads, liquidity estimates and liquidity / pool-creation writes. */\n public readonly positions: Positions;\n /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */\n public readonly swaps: Swaps;\n /** User token balances. */\n public readonly assets: Assets;\n /** USD prices, price series and the platform volume totals. */\n public readonly market: Market;\n /** Trading-competition seasons and rankings. */\n public readonly leaderboard: Leaderboard;\n /** Network-fee quotes (DryRun) signed with this client's signer. */\n public readonly fees: DexFees;\n /** The realtime stream endpoint {@link GSwap.stream} connects to. */\n public readonly dexBackendWsUrl: string;\n private readonly webSocketImpl: unknown;\n private readonly streamApiKey: string | undefined;\n private streamClient: GdexStreamService | undefined;\n\n /**\n * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * const symbols = await gSwap.symbols.list();\n * ```\n */\n constructor(options?: GSwapOptions) {\n const environment = GSWAP_ENVIRONMENTS[options?.env ?? 'prod'];\n this.dexBackendBaseUrl = trimTrailingSlash(\n options?.dexBackendBaseUrl ?? environment.dexBackendBaseUrl,\n );\n this.chainCallTimeoutMs = options?.chainCallTimeoutMs ?? 30_000;\n this.signer = options?.signer;\n this.walletAddress = options?.walletAddress;\n\n const httpClient = new HttpClient(\n options?.httpRequestor,\n this.chainCallTimeoutMs,\n options?.wire,\n );\n this.gateway = new ChainGateway({\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n chainCallTimeoutMs: this.chainCallTimeoutMs,\n ...(options?.wire === undefined ? {} : { wire: options.wire }),\n ...(options?.httpRequestor === undefined ? {} : { httpRequestor: options.httpRequestor }),\n ...(this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress }),\n });\n const lenient = { onInvalidEntry: options?.onInvalidEntry };\n this.symbols = new Symbols(this.gateway, lenient);\n // The services resolve tokens through the registry by default; the offline resolver sends the\n // caller's canonical symbols and keys as they are and never reads the registry.\n const resolver =\n options?.symbolResolution === 'canonical' ? new CanonicalSymbols() : this.symbols;\n this.quoting = new Quoting(this.gateway, resolver);\n this.pools = new Pools(this.gateway, resolver, lenient);\n const keyOptions = { uniqueKeyPrefix: options?.uniqueKeyPrefix, ...lenient };\n this.positions = new Positions(\n this.gateway,\n resolver,\n this.signer,\n this.walletAddress,\n keyOptions,\n );\n this.swaps = new Swaps(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);\n this.assets = new Assets(this.dexBackendBaseUrl, httpClient);\n this.market = new Market(this.dexBackendBaseUrl, httpClient, lenient);\n this.leaderboard = new Leaderboard(this.dexBackendBaseUrl, httpClient, lenient);\n this.fees = new DexFees(this.gateway, this.signer);\n this.dexBackendWsUrl =\n options?.dexBackendWsUrl ??\n (options?.dexBackendBaseUrl === undefined\n ? environment.dexBackendWsUrl\n : `${this.dexBackendBaseUrl.replace(/^http/u, 'ws')}/ws`);\n this.webSocketImpl = options?.webSocketImpl;\n this.streamApiKey = options?.streamApiKey;\n }\n\n /**\n * The realtime stream client for this environment (created on first use, not connected until you\n * call `connect()`).\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * await gSwap.stream.connect();\n * await gSwap.stream.subscribeLiquidity((event) => console.log(event.action, event.amount0));\n * ```\n */\n get stream(): GdexStreamService {\n this.streamClient ??= new GdexStreamService({\n url: this.dexBackendWsUrl,\n ...(this.webSocketImpl === undefined ? {} : { webSocketImpl: this.webSocketImpl }),\n ...(this.streamApiKey === undefined ? {} : { apiKey: this.streamApiKey }),\n });\n return this.streamClient;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gswap.js","names":["_defineProperty","GSwap","environment","GSWAP_ENVIRONMENTS","options","trimTrailingSlash","userRef","httpClient","HttpClient","ChainGateway","lenient","Symbols","resolver","CanonicalSymbols","Quoting","Pools","keyOptions","Positions","Swaps","Assets","Market","Leaderboard","Onramper","DexFees","GdexStreamService","value"],"sources":["../../../src/classes/gswap.ts"],"sourcesContent":["import { Assets } from './assets.js';\nimport { DexFees } from './dex_fees.js';\nimport { ChainGateway } from './gateway.js';\nimport { GdexStreamService } from './gdex_stream.js';\nimport { HttpClient } from './http_client.js';\nimport { Leaderboard } from './leaderboard.js';\nimport { Market } from './market.js';\nimport { Onramper } from './onramper.js';\nimport { Pools } from './pools.js';\nimport { Positions } from './positions.js';\nimport { Quoting } from './quoting.js';\nimport type { GalaChainSigner, HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { CanonicalSymbols, Symbols } from './symbols.js';\nimport type { InvalidEntryHandler } from '../utils/lenient.js';\nimport { userRef } from '../utils/validation.js';\nimport { Swaps } from './swaps.js';\nimport type { GSwapEnv } from '../types/env.js';\nimport { GSWAP_ENVIRONMENTS } from '../types/env.js';\n\n/** Options for constructing a backend-routed SDK client. */\nexport interface GSwapOptions {\n /** Signs every write. Without one, reads work and any write throws `NO_SIGNER`. */\n signer?: GalaChainSigner | undefined;\n /**\n * The selected account, sent as `X-Wallet-Address` on writes (attribution only; the chain\n * recovers the signer from the signature). Required for shadow writes. Any spelling of an\n * Ethereum account (`eth|<40 hex>` in any casing, `eth|0x...`, `0x...`, bare hex) is sent as\n * `eth|<EIP-55>`, `client|<id>` as written; a mixed-case spelling that is not the checksum is\n * refused at construction (`INVALID_WALLET_ADDRESS`).\n */\n walletAddress?: string | undefined;\n /** `'stage'` or `'prod'` swap backend preset; defaults to `'prod'`. */\n env?: GSwapEnv | undefined;\n /** Overrides the preset's swap backend base URL (a test or private deployment). */\n dexBackendBaseUrl?: string | undefined;\n /** HTTP transport for every request; defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000); `Infinity` arms no timer. */\n chainCallTimeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the read requests (see {@link WireOptions}). */\n wire?: WireOptions | undefined;\n /**\n * How tokens are turned into trading symbols. `'registry'` (default) reads the symbol registry\n * once (`GET /v2/trade/symbols`, cached) and accepts symbols or class keys. `'canonical'` makes\n * no registry request: the caller passes the backend's canonical trading symbols (from a quote,\n * an estimate or a position), reads send tokens and ticks exactly as given (composite keys\n * included) and the backend orients the pair; see {@link CanonicalSymbols}.\n */\n symbolResolution?: 'registry' | 'canonical' | undefined;\n /**\n * Told about every row of a pool, symbol, position, price, price-series, season or leaderboard\n * answer that was skipped as unusable (see {@link InvalidEntryHandler}); without it such rows are\n * skipped silently.\n */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n /** Realtime stream endpoint. Defaults to the environment's, or is derived from `dexBackendBaseUrl`. */\n dexBackendWsUrl?: string | undefined;\n /** WebSocket constructor for the realtime stream; required on Node.js older than 22. */\n webSocketImpl?: unknown;\n /**\n * `x-api-key` for the privileged stream view; server-side only, and it requires `webSocketImpl`\n * (see `GdexStreamConfig.apiKey`).\n */\n streamApiKey?: string | undefined;\n /**\n * Prefix of every write's `uniqueKey` (`<prefix><uuid>`). Defaults to `galaswap-operation-`,\n * what frontend_v2 and wallet_extension send; defi-backend does not depend on it.\n */\n uniqueKeyPrefix?: string | undefined;\n}\n\n/**\n * Main entry point for the current GalaChainDex SDK: one client bundling the services that read\n * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,\n * `market`, `leaderboard`, `onramper`, `symbols`, `fees`, `stream`). See {@link GSwapOptions} for\n * configuration.\n */\nexport class GSwap {\n /** The swap backend base URL every request goes to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */\n public readonly chainCallTimeoutMs: number;\n /** The signer given at construction, if any. */\n public readonly signer: GalaChainSigner | undefined;\n /**\n * The account given at construction, if any, in the gateway's spelling (`eth|<EIP-55>`;\n * `client|<id>` as given).\n */\n public readonly walletAddress: string | undefined;\n /** The chain-gateway client every other service reads and writes through. */\n public readonly gateway: ChainGateway;\n /** The trading-symbol registry. */\n public readonly symbols: Symbols;\n /** Read-only exact-input and exact-output quotes. */\n public readonly quoting: Quoting;\n /** Pool, slot0 and composite-pool reads. */\n public readonly pools: Pools;\n /** Position reads, liquidity estimates and liquidity / pool-creation writes. */\n public readonly positions: Positions;\n /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */\n public readonly swaps: Swaps;\n /** User token balances. */\n public readonly assets: Assets;\n /** USD prices, price series and the platform volume totals. */\n public readonly market: Market;\n /** Trading-competition seasons and rankings. */\n public readonly leaderboard: Leaderboard;\n /** The Onramper (fiat on-ramp) widget URL. */\n public readonly onramper: Onramper;\n /** Network-fee quotes (DryRun) signed with this client's signer. */\n public readonly fees: DexFees;\n /** The realtime stream endpoint {@link GSwap.stream} connects to. */\n public readonly dexBackendWsUrl: string;\n private readonly webSocketImpl: unknown;\n private readonly streamApiKey: string | undefined;\n private streamClient: GdexStreamService | undefined;\n\n /**\n * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * const symbols = await gSwap.symbols.list();\n * ```\n */\n constructor(options?: GSwapOptions) {\n const environment = GSWAP_ENVIRONMENTS[options?.env ?? 'prod'];\n this.dexBackendBaseUrl = trimTrailingSlash(\n options?.dexBackendBaseUrl ?? environment.dexBackendBaseUrl,\n );\n this.chainCallTimeoutMs = options?.chainCallTimeoutMs ?? 30_000;\n this.signer = options?.signer;\n this.walletAddress =\n options?.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n\n const httpClient = new HttpClient(\n options?.httpRequestor,\n this.chainCallTimeoutMs,\n options?.wire,\n );\n this.gateway = new ChainGateway({\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n chainCallTimeoutMs: this.chainCallTimeoutMs,\n ...(options?.wire === undefined ? {} : { wire: options.wire }),\n ...(options?.httpRequestor === undefined ? {} : { httpRequestor: options.httpRequestor }),\n ...(this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress }),\n });\n const lenient = { onInvalidEntry: options?.onInvalidEntry };\n this.symbols = new Symbols(this.gateway, lenient);\n // The services resolve tokens through the registry by default; the offline resolver sends the\n // caller's canonical symbols and keys as they are and never reads the registry.\n const resolver =\n options?.symbolResolution === 'canonical' ? new CanonicalSymbols() : this.symbols;\n this.quoting = new Quoting(this.gateway, resolver);\n this.pools = new Pools(this.gateway, resolver, lenient);\n const keyOptions = { uniqueKeyPrefix: options?.uniqueKeyPrefix, ...lenient };\n this.positions = new Positions(\n this.gateway,\n resolver,\n this.signer,\n this.walletAddress,\n keyOptions,\n );\n this.swaps = new Swaps(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);\n this.assets = new Assets(this.dexBackendBaseUrl, httpClient);\n this.market = new Market(this.dexBackendBaseUrl, httpClient, lenient);\n this.leaderboard = new Leaderboard(this.dexBackendBaseUrl, httpClient, lenient);\n this.onramper = new Onramper(this.dexBackendBaseUrl, httpClient);\n this.fees = new DexFees(this.gateway, this.signer);\n this.dexBackendWsUrl =\n options?.dexBackendWsUrl ??\n (options?.dexBackendBaseUrl === undefined\n ? environment.dexBackendWsUrl\n : `${this.dexBackendBaseUrl.replace(/^http/u, 'ws')}/ws`);\n this.webSocketImpl = options?.webSocketImpl;\n this.streamApiKey = options?.streamApiKey;\n }\n\n /**\n * The realtime stream client for this environment (created on first use, not connected until you\n * call `connect()`).\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * await gSwap.stream.connect();\n * await gSwap.stream.subscribeLiquidity((event) => console.log(event.action, event.amount0));\n * ```\n */\n get stream(): GdexStreamService {\n this.streamClient ??= new GdexStreamService({\n url: this.dexBackendWsUrl,\n ...(this.webSocketImpl === undefined ? {} : { webSocketImpl: this.webSocketImpl }),\n ...(this.streamApiKey === undefined ? {} : { apiKey: this.streamApiKey }),\n });\n return this.streamClient;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{GSwapSDKError as e}from"./gswap_sdk_error.js";import{HttpClient as t}from"./http_client.js";import{asEntryRecord as n}from"../utils/lenient.js";const r=[`buy`,`sell`,`swap`],i=[`defaultFiat`,`onlyCryptoNetworks`,`defaultPaymentMethod`,`defaultCrypto`,`onlyPaymentMethods`,`excludePaymentMethods`,`onlyFiat`,`excludeFiat`,`isAddressEditable`,`networkPrefix`],a=[`defaultAmount`,`sellDefaultAmount`];function o(t,n){return new e(`INVALID_DTO`,{method:`onramper.generateWidgetUrl`,field:t,expected:n})}function s(e){if(typeof e!=`object`||!e)throw o(`request`,`an object`);if(typeof e.walletAddress!=`string`||e.walletAddress.trim()===``)throw o(`walletAddress`,`a non-empty string`);let t={walletAddress:e.walletAddress};if(e.mode!==void 0){if(!r.includes(e.mode))throw o(`mode`,r.join(`, `));t.mode=e.mode}for(let n of i){let r=e[n];if(r!==void 0){if(typeof r!=`string`)throw o(n,`a string`);t[n]=r}}for(let n of a){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<0)throw o(n,`a finite number, 0 or more`);t[n]=r}}return t}function c(t){let r=n(n(t)?.data)?.url;if(typeof r==`string`&&r!==``)try{return new URL(r),r}catch{}throw new e(`INVALID_CHAIN_RESPONSE`,{resource:`onramper widget url`},{body:t,write:!1})}var l=class{constructor(e,t){this.dexBackendBaseUrl=e,this.httpClient=t}async generateWidgetUrl(e){let t=s(e);return c(await this.httpClient.sendPostRequest(this.dexBackendBaseUrl,`/api/v1/onramper`,`/generate-widget-url`,t))}};function u(e){return new l(e.dexBackendBaseUrl.replace(/\/$/u,``),new t(e.httpRequestor,e.timeoutMs,e.wire))}export{r as ONRAMPER_MODES,l as Onramper,u as createOnramper};
2
+ //# sourceMappingURL=onramper.js.map