@lasersell/lasersell-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xen LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # @lasersell/lasersell-sdk
2
+
3
+ TypeScript SDK for the LaserSell API.
4
+
5
+ Modules:
6
+ - `exit-api`: build unsigned buy/sell transactions.
7
+ - `stream`: websocket client, protocol types, and session helpers.
8
+ - `tx`: sign/encode/send Solana transactions.
9
+ - `retry`: shared retry helpers.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @lasersell/lasersell-sdk
15
+ ```
16
+
17
+ For local development in this repository:
18
+
19
+ ```bash
20
+ cd lasersell-sdk/js
21
+ npm install
22
+ ```
23
+
24
+ ## API Surface
25
+
26
+ - LaserSell API client:
27
+ - `ExitApiClient`
28
+ - `BuildBuyTxRequest`, `BuildSellTxRequest`, `BuildTxResponse`
29
+ - Stream client and session:
30
+ - `StreamClient`, `StreamSession`
31
+ - `StreamConfigure`, `StreamEvent`, `PositionHandle`
32
+ - Stream protocol types (ported inline):
33
+ - `ClientMessage`, `ServerMessage`, `StrategyConfigMsg`, `MarketContextMsg`
34
+ - Transaction helpers:
35
+ - `signUnsignedTx`, `encodeSignedTx`
36
+ - `sendTransaction`, `sendTransactionB64To`
37
+ - `sendTargetRpc`, `sendTargetHeliusSender`, `sendTargetAstralane`
38
+
39
+ ## Build a sell transaction
40
+
41
+ ```ts
42
+ import { ExitApiClient, type BuildSellTxRequest } from "@lasersell/lasersell-sdk";
43
+
44
+ const client = ExitApiClient.withApiKey("REPLACE_WITH_API_KEY");
45
+
46
+ const request: BuildSellTxRequest = {
47
+ mint: "REPLACE_WITH_MINT",
48
+ user_pubkey: "REPLACE_WITH_WALLET_PUBKEY",
49
+ amount_tokens: 1_000_000,
50
+ slippage_bps: 2_000,
51
+ output: "SOL",
52
+ };
53
+
54
+ const response = await client.buildSellTx(request);
55
+ console.log(response.tx);
56
+ ```
57
+
58
+ ## Stream + auto-sell flow
59
+
60
+ ```ts
61
+ import {
62
+ StreamClient,
63
+ StreamSession,
64
+ singleWalletStreamConfigureOptional,
65
+ signUnsignedTx,
66
+ sendTransaction,
67
+ sendTargetHeliusSender,
68
+ } from "@lasersell/lasersell-sdk";
69
+ import { Keypair } from "@solana/web3.js";
70
+
71
+ const client = new StreamClient("REPLACE_WITH_API_KEY");
72
+ const session = await StreamSession.connect(
73
+ client,
74
+ singleWalletStreamConfigureOptional(
75
+ "REPLACE_WITH_WALLET_PUBKEY",
76
+ {},
77
+ 45, // timeout-only strategy is valid
78
+ ),
79
+ );
80
+
81
+ const signer = Keypair.generate();
82
+
83
+ while (true) {
84
+ const event = await session.recv();
85
+ if (event === null) break;
86
+
87
+ if (event.type === "exit_signal_with_tx" && event.message.type === "exit_signal_with_tx") {
88
+ const signed = signUnsignedTx(event.message.unsigned_tx_b64, signer);
89
+ const signature = await sendTransaction(sendTargetHeliusSender(), signed);
90
+ console.log(signature);
91
+ }
92
+ }
93
+ ```
94
+
95
+ `deadline_timeout_sec` is enforced client-side by `StreamSession` timers and is not sent as part of wire strategy.
96
+ Use `session.updateStrategy(...)` when changing strategy so local deadline timers stay in sync (pass a second `deadlineTimeoutSec` argument to change local deadline timing).
97
+ Use `singleWalletStreamConfigureOptional(...)` / `strategyConfigFromOptional(...)` to omit TP/SL fields; at least one of take profit, stop loss, or timeout must be enabled.
98
+
99
+ ## Examples
100
+
101
+ Runnable examples live in `examples/`:
102
+
103
+ - `examples/build_buy.ts`: build unsigned buy tx
104
+ - `examples/build_sell.ts`: build unsigned sell tx
105
+ - `examples/build_and_send_sell.ts`: build, sign, and submit sell tx
106
+ - `examples/auto_sell.ts`: stream listener that signs and submits exits
107
+
108
+ See `examples/README.md` for required placeholders/inputs and exact run commands.
109
+
110
+ ## Build
111
+
112
+ ```bash
113
+ npm run build
114
+ ```
@@ -0,0 +1,87 @@
1
+ import { type RetryPolicy } from "./retry.js";
2
+ import type { MarketContextMsg } from "./stream/proto.js";
3
+ export declare const EXIT_API_BASE_URL = "https://api.lasersell.io";
4
+ export declare const LOCAL_EXIT_API_BASE_URL = "http://localhost:8080";
5
+ export declare const EXIT_API_DEFAULTS: {
6
+ readonly connect_timeout_ms: 200;
7
+ readonly attempt_timeout_ms: 900;
8
+ readonly max_attempts: 2;
9
+ readonly backoff_ms: 25;
10
+ readonly jitter_ms: 25;
11
+ };
12
+ export type SellOutput = "SOL" | "USD1";
13
+ /** Transaction send mode for the exit API. */
14
+ export type SendMode = "helius_sender" | "astralane" | "rpc";
15
+ export interface BuildSellTxRequest {
16
+ mint: string;
17
+ user_pubkey: string;
18
+ amount_tokens: number;
19
+ slippage_bps?: number;
20
+ mode?: string;
21
+ output?: SellOutput;
22
+ market_context?: MarketContextMsg;
23
+ /** Transaction send mode: `"helius_sender"`, `"astralane"`, or `"rpc"`. */
24
+ send_mode?: SendMode;
25
+ /** Optional tip amount in lamports for the transaction. */
26
+ tip_lamports?: number;
27
+ }
28
+ export interface BuildBuyTxRequest {
29
+ mint: string;
30
+ user_pubkey: string;
31
+ amount_quote_units: number;
32
+ slippage_bps?: number;
33
+ mode?: string;
34
+ /** Transaction send mode: `"helius_sender"`, `"astralane"`, or `"rpc"`. */
35
+ send_mode?: SendMode;
36
+ /** Optional tip amount in lamports for the transaction. */
37
+ tip_lamports?: number;
38
+ }
39
+ export interface BuildTxResponse {
40
+ tx: string;
41
+ route?: unknown;
42
+ debug?: unknown;
43
+ }
44
+ export interface ExitApiClientOptions {
45
+ connect_timeout_ms: number;
46
+ attempt_timeout_ms: number;
47
+ retry_policy: RetryPolicy;
48
+ fetch_impl: FetchLike;
49
+ }
50
+ export type ExitApiErrorKind = "transport" | "http_status" | "envelope_status" | "parse";
51
+ export declare class ExitApiError extends Error {
52
+ readonly kind: ExitApiErrorKind;
53
+ readonly status?: number;
54
+ readonly body?: string;
55
+ readonly detail?: string;
56
+ private constructor();
57
+ static transport(cause: unknown): ExitApiError;
58
+ static httpStatus(status: number, body: string): ExitApiError;
59
+ static envelopeStatus(status: string, detail: string): ExitApiError;
60
+ static parse(message: string, cause?: unknown): ExitApiError;
61
+ isRetryable(): boolean;
62
+ }
63
+ export declare class ExitApiClient {
64
+ private readonly apiKey?;
65
+ private readonly connectTimeoutMs;
66
+ private readonly attemptTimeoutMs;
67
+ private readonly retryPolicy;
68
+ private readonly fetchImpl;
69
+ private local;
70
+ private baseUrlOverride?;
71
+ constructor(apiKey?: string, options?: Partial<ExitApiClientOptions>);
72
+ static withApiKey(apiKey: string): ExitApiClient;
73
+ static withOptions(apiKey: string | undefined, options: Partial<ExitApiClientOptions>): ExitApiClient;
74
+ withLocalMode(local: boolean): this;
75
+ withBaseUrl(baseUrl: string): this;
76
+ buildSellTx(request: BuildSellTxRequest): Promise<BuildTxResponse>;
77
+ buildSellTxB64(request: BuildSellTxRequest): Promise<string>;
78
+ buildBuyTx(request: BuildBuyTxRequest): Promise<BuildTxResponse>;
79
+ private buildTx;
80
+ private endpoint;
81
+ private baseUrl;
82
+ private sendAttempt;
83
+ }
84
+ export declare function parseBuildTxResponse(body: string): BuildTxResponse;
85
+ type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
86
+ export declare const DEFAULT_RETRY_POLICY: RetryPolicy;
87
+ export {};
@@ -0,0 +1,238 @@
1
+ import { LOW_LATENCY_RETRY_POLICY, retryAsync, } from "./retry.js";
2
+ const ERROR_BODY_SNIPPET_LEN = 220;
3
+ export const EXIT_API_BASE_URL = "https://api.lasersell.io";
4
+ export const LOCAL_EXIT_API_BASE_URL = "http://localhost:8080";
5
+ export const EXIT_API_DEFAULTS = {
6
+ connect_timeout_ms: 200,
7
+ attempt_timeout_ms: 900,
8
+ max_attempts: 2,
9
+ backoff_ms: 25,
10
+ jitter_ms: 25,
11
+ };
12
+ export class ExitApiError extends Error {
13
+ kind;
14
+ status;
15
+ body;
16
+ detail;
17
+ constructor(kind, message, options) {
18
+ super(message, { cause: options?.cause });
19
+ this.name = "ExitApiError";
20
+ this.kind = kind;
21
+ this.status = options?.status;
22
+ this.body = options?.body;
23
+ this.detail = options?.detail;
24
+ }
25
+ static transport(cause) {
26
+ return new ExitApiError("transport", `request failed: ${stringifyError(cause)}`, { cause });
27
+ }
28
+ static httpStatus(status, body) {
29
+ return new ExitApiError("http_status", `http status ${status}: ${body}`, {
30
+ status,
31
+ body,
32
+ });
33
+ }
34
+ static envelopeStatus(status, detail) {
35
+ return new ExitApiError("envelope_status", `exit-api status ${status}: ${detail}`, { detail });
36
+ }
37
+ static parse(message, cause) {
38
+ return new ExitApiError("parse", `failed to parse response: ${message}`, {
39
+ cause,
40
+ });
41
+ }
42
+ isRetryable() {
43
+ if (this.kind === "transport") {
44
+ return true;
45
+ }
46
+ if (this.kind === "http_status") {
47
+ return ((this.status !== undefined && this.status >= 500) || this.status === 429);
48
+ }
49
+ return false;
50
+ }
51
+ }
52
+ export class ExitApiClient {
53
+ apiKey;
54
+ connectTimeoutMs;
55
+ attemptTimeoutMs;
56
+ retryPolicy;
57
+ fetchImpl;
58
+ local = false;
59
+ baseUrlOverride;
60
+ constructor(apiKey, options = {}) {
61
+ this.apiKey = apiKey;
62
+ this.connectTimeoutMs =
63
+ options.connect_timeout_ms ?? EXIT_API_DEFAULTS.connect_timeout_ms;
64
+ this.attemptTimeoutMs =
65
+ options.attempt_timeout_ms ?? EXIT_API_DEFAULTS.attempt_timeout_ms;
66
+ this.retryPolicy = options.retry_policy
67
+ ? { ...options.retry_policy }
68
+ : {
69
+ max_attempts: EXIT_API_DEFAULTS.max_attempts,
70
+ initial_backoff_ms: EXIT_API_DEFAULTS.backoff_ms,
71
+ max_backoff_ms: EXIT_API_DEFAULTS.backoff_ms,
72
+ jitter_ms: EXIT_API_DEFAULTS.jitter_ms,
73
+ };
74
+ this.fetchImpl = options.fetch_impl ?? globalThis.fetch;
75
+ if (typeof this.fetchImpl !== "function") {
76
+ throw new Error("No fetch implementation available. Provide options.fetch_impl in environments without global fetch.");
77
+ }
78
+ }
79
+ static withApiKey(apiKey) {
80
+ return new ExitApiClient(apiKey);
81
+ }
82
+ static withOptions(apiKey, options) {
83
+ return new ExitApiClient(apiKey, options);
84
+ }
85
+ withLocalMode(local) {
86
+ this.local = local;
87
+ return this;
88
+ }
89
+ withBaseUrl(baseUrl) {
90
+ this.baseUrlOverride = baseUrl.trim().replace(/\/+$/, "");
91
+ return this;
92
+ }
93
+ async buildSellTx(request) {
94
+ return await this.buildTx("/v1/sell", request);
95
+ }
96
+ async buildSellTxB64(request) {
97
+ const response = await this.buildSellTx(request);
98
+ return response.tx;
99
+ }
100
+ async buildBuyTx(request) {
101
+ return await this.buildTx("/v1/buy", request);
102
+ }
103
+ async buildTx(path, request) {
104
+ const endpoint = this.endpoint(path);
105
+ return await retryAsync(this.retryPolicy, async () => await this.sendAttempt(endpoint, request), (error) => error instanceof ExitApiError && error.isRetryable());
106
+ }
107
+ endpoint(path) {
108
+ return `${this.baseUrl()}${path}`;
109
+ }
110
+ baseUrl() {
111
+ if (this.baseUrlOverride !== undefined) {
112
+ return this.baseUrlOverride;
113
+ }
114
+ if (this.local) {
115
+ return LOCAL_EXIT_API_BASE_URL;
116
+ }
117
+ return EXIT_API_BASE_URL;
118
+ }
119
+ async sendAttempt(endpoint, request) {
120
+ const timeoutMs = Math.max(this.connectTimeoutMs, this.attemptTimeoutMs);
121
+ const controller = new AbortController();
122
+ const timer = setTimeout(() => {
123
+ controller.abort();
124
+ }, timeoutMs);
125
+ try {
126
+ const headers = {
127
+ "content-type": "application/json",
128
+ };
129
+ if (this.apiKey !== undefined) {
130
+ headers["x-api-key"] = this.apiKey;
131
+ }
132
+ const response = await this.fetchImpl(endpoint, {
133
+ method: "POST",
134
+ headers,
135
+ body: JSON.stringify(request),
136
+ signal: controller.signal,
137
+ });
138
+ const body = await response.text();
139
+ if (!response.ok) {
140
+ throw ExitApiError.httpStatus(response.status, summarizeErrorBody(body));
141
+ }
142
+ return parseBuildTxResponse(body);
143
+ }
144
+ catch (error) {
145
+ if (error instanceof ExitApiError) {
146
+ throw error;
147
+ }
148
+ throw ExitApiError.transport(error);
149
+ }
150
+ finally {
151
+ clearTimeout(timer);
152
+ }
153
+ }
154
+ }
155
+ export function parseBuildTxResponse(body) {
156
+ let parsed;
157
+ try {
158
+ parsed = JSON.parse(body);
159
+ }
160
+ catch (error) {
161
+ throw ExitApiError.parse("response was not valid JSON", error);
162
+ }
163
+ const obj = asRecord(parsed, "response");
164
+ const taggedStatus = asOptionalString(obj.status);
165
+ if (taggedStatus !== undefined) {
166
+ if (taggedStatus.toLowerCase() === "ok") {
167
+ const tx = asOptionalString(obj.tx) ?? asOptionalString(obj.unsigned_tx_b64);
168
+ if (tx === undefined) {
169
+ throw ExitApiError.parse("status=ok payload missing tx");
170
+ }
171
+ return {
172
+ tx,
173
+ route: obj.route,
174
+ debug: obj.debug,
175
+ };
176
+ }
177
+ const detail = asOptionalString(obj.reason) ??
178
+ asOptionalString(obj.message) ??
179
+ asOptionalString(obj.error) ??
180
+ "unknown failure";
181
+ throw ExitApiError.envelopeStatus(taggedStatus, detail);
182
+ }
183
+ const legacyTx = asOptionalString(obj.unsigned_tx_b64);
184
+ if (legacyTx !== undefined) {
185
+ return {
186
+ tx: legacyTx,
187
+ route: obj.route,
188
+ debug: obj.debug,
189
+ };
190
+ }
191
+ const bareTx = asOptionalString(obj.tx);
192
+ if (bareTx !== undefined) {
193
+ return {
194
+ tx: bareTx,
195
+ route: obj.route,
196
+ debug: obj.debug,
197
+ };
198
+ }
199
+ throw ExitApiError.parse("response did not match any supported schema");
200
+ }
201
+ function summarizeErrorBody(body) {
202
+ try {
203
+ const parsed = JSON.parse(body);
204
+ const obj = asRecord(parsed, "error body");
205
+ const message = asOptionalString(obj.error) ??
206
+ asOptionalString(obj.message) ??
207
+ asOptionalString(obj.reason);
208
+ if (message !== undefined) {
209
+ return message;
210
+ }
211
+ }
212
+ catch {
213
+ // Ignore JSON parse errors and fall back to body snippet.
214
+ }
215
+ return body.slice(0, ERROR_BODY_SNIPPET_LEN);
216
+ }
217
+ function asRecord(value, path) {
218
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
219
+ throw ExitApiError.parse(`${path} must be an object`);
220
+ }
221
+ return value;
222
+ }
223
+ function asOptionalString(value) {
224
+ if (typeof value === "string") {
225
+ return value;
226
+ }
227
+ return undefined;
228
+ }
229
+ function stringifyError(error) {
230
+ if (error instanceof Error) {
231
+ return `${error.name}: ${error.message}`;
232
+ }
233
+ return String(error);
234
+ }
235
+ export const DEFAULT_RETRY_POLICY = {
236
+ ...LOW_LATENCY_RETRY_POLICY,
237
+ };
238
+ //# sourceMappingURL=exitApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exitApi.js","sourceRoot":"","sources":["../src/exitApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from "./exitApi.js";
2
+ export * from "./retry.js";
3
+ export * from "./tx.js";
4
+ export * from "./stream/index.js";
5
+ export * as stream from "./stream/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./exitApi.js";
2
+ export * from "./retry.js";
3
+ export * from "./tx.js";
4
+ export * from "./stream/index.js";
5
+ export * as stream from "./stream/index.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,mBAAmB,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface RetryPolicy {
2
+ max_attempts: number;
3
+ initial_backoff_ms: number;
4
+ max_backoff_ms: number;
5
+ jitter_ms: number;
6
+ }
7
+ export declare const LOW_LATENCY_RETRY_POLICY: RetryPolicy;
8
+ export declare function lowLatencyRetryPolicy(): RetryPolicy;
9
+ export declare function delayForAttempt(policy: RetryPolicy, attempt: number): number;
10
+ export declare function retryAsync<T, E>(policy: RetryPolicy, op: (attempt: number) => Promise<T>, shouldRetry: (error: E) => boolean): Promise<T>;
11
+ export declare class TimeoutError extends Error {
12
+ readonly timeout_ms: number;
13
+ constructor(timeoutMs: number, message?: string);
14
+ }
15
+ export declare function withTimeout<T>(timeoutMs: number, promise: Promise<T>): Promise<T>;
package/dist/retry.js ADDED
@@ -0,0 +1,74 @@
1
+ export const LOW_LATENCY_RETRY_POLICY = {
2
+ max_attempts: 2,
3
+ initial_backoff_ms: 25,
4
+ max_backoff_ms: 100,
5
+ jitter_ms: 25,
6
+ };
7
+ export function lowLatencyRetryPolicy() {
8
+ return { ...LOW_LATENCY_RETRY_POLICY };
9
+ }
10
+ export function delayForAttempt(policy, attempt) {
11
+ let delay = Math.max(0, policy.initial_backoff_ms);
12
+ for (let i = 1; i < attempt; i += 1) {
13
+ delay = Math.min(delay * 2, Math.max(0, policy.max_backoff_ms));
14
+ }
15
+ return delay + jitterDurationMs(Math.max(0, policy.jitter_ms));
16
+ }
17
+ export async function retryAsync(policy, op, shouldRetry) {
18
+ const maxAttempts = Math.max(1, policy.max_attempts);
19
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
20
+ try {
21
+ return await op(attempt);
22
+ }
23
+ catch (error) {
24
+ const typedError = error;
25
+ if (attempt >= maxAttempts || !shouldRetry(typedError)) {
26
+ throw typedError;
27
+ }
28
+ const delay = delayForAttempt(policy, attempt);
29
+ if (delay > 0) {
30
+ await sleep(delay);
31
+ }
32
+ }
33
+ }
34
+ throw new Error("retryAsync reached an unreachable state");
35
+ }
36
+ export class TimeoutError extends Error {
37
+ timeout_ms;
38
+ constructor(timeoutMs, message = "operation timed out") {
39
+ super(message);
40
+ this.name = "TimeoutError";
41
+ this.timeout_ms = timeoutMs;
42
+ }
43
+ }
44
+ export async function withTimeout(timeoutMs, promise) {
45
+ if (timeoutMs <= 0) {
46
+ return promise;
47
+ }
48
+ return await new Promise((resolve, reject) => {
49
+ const timer = setTimeout(() => {
50
+ reject(new TimeoutError(timeoutMs));
51
+ }, timeoutMs);
52
+ promise
53
+ .then((value) => {
54
+ clearTimeout(timer);
55
+ resolve(value);
56
+ })
57
+ .catch((error) => {
58
+ clearTimeout(timer);
59
+ reject(error);
60
+ });
61
+ });
62
+ }
63
+ function jitterDurationMs(maxJitterMs) {
64
+ if (maxJitterMs <= 0) {
65
+ return 0;
66
+ }
67
+ return Math.floor(Math.random() * (maxJitterMs + 1));
68
+ }
69
+ function sleep(ms) {
70
+ return new Promise((resolve) => {
71
+ setTimeout(resolve, ms);
72
+ });
73
+ }
74
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}