@lightsparkdev/lightspark-sdk 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/.fossa.yml +6 -0
  2. package/.prettierrc +1 -0
  3. package/.turbo/turbo-build.log +19 -0
  4. package/.turbo/turbo-lint.log +3 -0
  5. package/CHANGELOG.md +49 -0
  6. package/LICENSE +201 -0
  7. package/README.md +137 -0
  8. package/dist/Withdrawal-17e1c8af.d.ts +1672 -0
  9. package/dist/Withdrawal-27a4d10d.d.ts +1672 -0
  10. package/dist/chunk-3VRI7CHE.js +5508 -0
  11. package/dist/chunk-AGEUDR2V.js +4498 -0
  12. package/dist/chunk-N27QHRE4.js +5508 -0
  13. package/dist/client-3bba3f64.d.ts +1302 -0
  14. package/dist/index.cjs +6633 -0
  15. package/dist/index.d.ts +15 -0
  16. package/dist/index.js +1177 -0
  17. package/dist/objects/index.cjs +5347 -0
  18. package/dist/objects/index.d.ts +3 -0
  19. package/dist/objects/index.js +88 -0
  20. package/examples/node-scripts/authHelpers.ts +20 -0
  21. package/examples/node-scripts/createInvoice.ts +64 -0
  22. package/examples/node-scripts/example.ts +288 -0
  23. package/examples/node-scripts/getAccountDashboard.ts +24 -0
  24. package/examples/node-scripts/getNodeChannels.ts +34 -0
  25. package/examples/node-scripts/internalAuthHelpers.ts +26 -0
  26. package/examples/node-scripts/internal_example.ts +296 -0
  27. package/examples/node-scripts/package-lock.json +887 -0
  28. package/examples/node-scripts/package.json +22 -0
  29. package/examples/node-scripts/prettyPrintJsonForDocs.ts +62 -0
  30. package/examples/node-scripts/tsconfig.json +27 -0
  31. package/examples/oauth-example/README.md +19 -0
  32. package/examples/oauth-example/package-lock.json +16071 -0
  33. package/examples/oauth-example/package.json +50 -0
  34. package/examples/oauth-example/public/favicon.ico +0 -0
  35. package/examples/oauth-example/public/index.html +43 -0
  36. package/examples/oauth-example/public/logo192.png +0 -0
  37. package/examples/oauth-example/public/logo512.png +0 -0
  38. package/examples/oauth-example/public/manifest.json +25 -0
  39. package/examples/oauth-example/public/robots.txt +3 -0
  40. package/examples/oauth-example/src/App.css +7 -0
  41. package/examples/oauth-example/src/App.test.tsx +12 -0
  42. package/examples/oauth-example/src/App.tsx +16 -0
  43. package/examples/oauth-example/src/auth/AuthContext.ts +8 -0
  44. package/examples/oauth-example/src/auth/AuthProvider.tsx +44 -0
  45. package/examples/oauth-example/src/auth/RequireAuth.tsx +19 -0
  46. package/examples/oauth-example/src/auth/oauthProvider.ts +35 -0
  47. package/examples/oauth-example/src/components/Button.tsx +39 -0
  48. package/examples/oauth-example/src/components/CurrencyAmount.tsx +117 -0
  49. package/examples/oauth-example/src/components/Dashboard.tsx +158 -0
  50. package/examples/oauth-example/src/components/Table.tsx +22 -0
  51. package/examples/oauth-example/src/hooks/useAccountInfo.tsx +31 -0
  52. package/examples/oauth-example/src/icons/BitcoinB.tsx +20 -0
  53. package/examples/oauth-example/src/icons/Icon.tsx +121 -0
  54. package/examples/oauth-example/src/icons/Satoshi.tsx +28 -0
  55. package/examples/oauth-example/src/index.css +13 -0
  56. package/examples/oauth-example/src/index.tsx +23 -0
  57. package/examples/oauth-example/src/lightsparkclient/LightsparkClientContext.ts +10 -0
  58. package/examples/oauth-example/src/lightsparkclient/LightsparkClientProvider.tsx +53 -0
  59. package/examples/oauth-example/src/logo.svg +1 -0
  60. package/examples/oauth-example/src/pages/DashboardPage.tsx +71 -0
  61. package/examples/oauth-example/src/pages/LoginPage.tsx +63 -0
  62. package/examples/oauth-example/src/react-app-env.d.ts +1 -0
  63. package/examples/oauth-example/src/reportWebVitals.ts +15 -0
  64. package/examples/oauth-example/src/routes/index.tsx +15 -0
  65. package/examples/oauth-example/src/setupTests.ts +5 -0
  66. package/examples/oauth-example/src/utils/currency.ts +483 -0
  67. package/examples/oauth-example/tsconfig.json +20 -0
  68. package/examples/streaming-wallet-extension/.fossa.yml +6 -0
  69. package/examples/streaming-wallet-extension/README.md +17 -0
  70. package/examples/streaming-wallet-extension/craco.config.js +58 -0
  71. package/examples/streaming-wallet-extension/package-lock.json +18260 -0
  72. package/examples/streaming-wallet-extension/package.json +77 -0
  73. package/examples/streaming-wallet-extension/public/index.html +24 -0
  74. package/examples/streaming-wallet-extension/public/lightspark_full.png +0 -0
  75. package/examples/streaming-wallet-extension/public/lightspark_icon_circle.png +0 -0
  76. package/examples/streaming-wallet-extension/public/manifest.json +43 -0
  77. package/examples/streaming-wallet-extension/public/robots.txt +3 -0
  78. package/examples/streaming-wallet-extension/src/App.css +53 -0
  79. package/examples/streaming-wallet-extension/src/App.tsx +425 -0
  80. package/examples/streaming-wallet-extension/src/auth/AccountStorage.ts +28 -0
  81. package/examples/streaming-wallet-extension/src/auth/DemoAccountProvider.ts +99 -0
  82. package/examples/streaming-wallet-extension/src/auth/StreamingDemoCredentials.ts +10 -0
  83. package/examples/streaming-wallet-extension/src/background/PaymentStrategy.ts +36 -0
  84. package/examples/streaming-wallet-extension/src/background/PlaybackRange.ts +31 -0
  85. package/examples/streaming-wallet-extension/src/background/StreamingInvoiceHolder.ts +33 -0
  86. package/examples/streaming-wallet-extension/src/background/TransactionObserver.ts +66 -0
  87. package/examples/streaming-wallet-extension/src/background/VideoPlaybackRanges.ts +38 -0
  88. package/examples/streaming-wallet-extension/src/background/VideoProgressCache.ts +87 -0
  89. package/examples/streaming-wallet-extension/src/background/background.ts +145 -0
  90. package/examples/streaming-wallet-extension/src/background/messageHandling.ts +185 -0
  91. package/examples/streaming-wallet-extension/src/common/datetimes.ts +28 -0
  92. package/examples/streaming-wallet-extension/src/common/settings.ts +12 -0
  93. package/examples/streaming-wallet-extension/src/common/storage.ts +8 -0
  94. package/examples/streaming-wallet-extension/src/common/streamingTabs.ts +27 -0
  95. package/examples/streaming-wallet-extension/src/common/types.tsx +23 -0
  96. package/examples/streaming-wallet-extension/src/components/CirclePlusIcon.tsx +19 -0
  97. package/examples/streaming-wallet-extension/src/components/CurrencyAmount.tsx +110 -0
  98. package/examples/streaming-wallet-extension/src/components/CurrencyAmountRaw.tsx +195 -0
  99. package/examples/streaming-wallet-extension/src/components/LeftArrow.tsx +21 -0
  100. package/examples/streaming-wallet-extension/src/components/Loading.tsx +151 -0
  101. package/examples/streaming-wallet-extension/src/components/StreamingTransactionChip.tsx +95 -0
  102. package/examples/streaming-wallet-extension/src/components/TransactionRow.tsx +93 -0
  103. package/examples/streaming-wallet-extension/src/contentscript/content.ts +123 -0
  104. package/examples/streaming-wallet-extension/src/contentscript/lightsparkDemoDom.tsx +113 -0
  105. package/examples/streaming-wallet-extension/src/contentscript/videoElementParsers.ts +92 -0
  106. package/examples/streaming-wallet-extension/src/index.css +16 -0
  107. package/examples/streaming-wallet-extension/src/index.tsx +11 -0
  108. package/examples/streaming-wallet-extension/src/lightsparkClientProvider.tsx +26 -0
  109. package/examples/streaming-wallet-extension/src/react-app-env.d.ts +1 -0
  110. package/examples/streaming-wallet-extension/src/types/Messages.ts +17 -0
  111. package/examples/streaming-wallet-extension/tsconfig.json +20 -0
  112. package/package.json +87 -0
  113. package/src/auth/AccountTokenAuthProvider.ts +37 -0
  114. package/src/auth/index.ts +3 -0
  115. package/src/client.ts +759 -0
  116. package/src/graphql/BitcoinFeeEstimate.ts +13 -0
  117. package/src/graphql/CreateApiToken.ts +22 -0
  118. package/src/graphql/CreateInvoice.ts +18 -0
  119. package/src/graphql/CreateNodeWalletAddress.ts +13 -0
  120. package/src/graphql/CurrentAccount.ts +13 -0
  121. package/src/graphql/DecodeInvoice.ts +16 -0
  122. package/src/graphql/DeleteApiToken.ts +13 -0
  123. package/src/graphql/FundNode.ts +18 -0
  124. package/src/graphql/LightningFeeEstimateForInvoice.ts +21 -0
  125. package/src/graphql/LightningFeeEstimateForNode.ts +21 -0
  126. package/src/graphql/MultiNodeDashboard.ts +118 -0
  127. package/src/graphql/PayInvoice.ts +29 -0
  128. package/src/graphql/RecoverNodeSigningKey.ts +15 -0
  129. package/src/graphql/RequestWithdrawal.ts +25 -0
  130. package/src/graphql/SendPayment.ts +29 -0
  131. package/src/graphql/SingleNodeDashboard.ts +116 -0
  132. package/src/graphql/TransactionSubscription.ts +16 -0
  133. package/src/graphql/TransactionsForNode.ts +42 -0
  134. package/src/index.ts +5 -0
  135. package/src/objects/Account.ts +1222 -0
  136. package/src/objects/AccountToApiTokensConnection.ts +50 -0
  137. package/src/objects/AccountToChannelsConnection.ts +35 -0
  138. package/src/objects/AccountToNodesConnection.ts +62 -0
  139. package/src/objects/AccountToPaymentRequestsConnection.ts +50 -0
  140. package/src/objects/AccountToTransactionsConnection.ts +112 -0
  141. package/src/objects/ApiToken.ts +80 -0
  142. package/src/objects/BitcoinNetwork.ts +19 -0
  143. package/src/objects/BlockchainBalance.ts +102 -0
  144. package/src/objects/Channel.ts +283 -0
  145. package/src/objects/ChannelClosingTransaction.ts +150 -0
  146. package/src/objects/ChannelFees.ts +34 -0
  147. package/src/objects/ChannelOpeningTransaction.ts +150 -0
  148. package/src/objects/ChannelStatus.ts +25 -0
  149. package/src/objects/ChannelToTransactionsConnection.ts +86 -0
  150. package/src/objects/CreateApiTokenInput.ts +22 -0
  151. package/src/objects/CreateApiTokenOutput.ts +41 -0
  152. package/src/objects/CreateInvoiceInput.ts +27 -0
  153. package/src/objects/CreateInvoiceOutput.ts +21 -0
  154. package/src/objects/CreateNodeWalletAddressInput.ts +15 -0
  155. package/src/objects/CreateNodeWalletAddressOutput.ts +27 -0
  156. package/src/objects/CurrencyAmount.ts +55 -0
  157. package/src/objects/CurrencyUnit.ts +25 -0
  158. package/src/objects/DeleteApiTokenInput.ts +13 -0
  159. package/src/objects/DeleteApiTokenOutput.ts +23 -0
  160. package/src/objects/Deposit.ts +144 -0
  161. package/src/objects/Entity.ts +868 -0
  162. package/src/objects/FeeEstimate.ts +39 -0
  163. package/src/objects/FundNodeInput.ts +16 -0
  164. package/src/objects/FundNodeOutput.ts +28 -0
  165. package/src/objects/GraphNode.ts +110 -0
  166. package/src/objects/Hop.ts +108 -0
  167. package/src/objects/HtlcAttemptFailureCode.ts +65 -0
  168. package/src/objects/IncomingPayment.ts +141 -0
  169. package/src/objects/IncomingPaymentAttempt.ts +96 -0
  170. package/src/objects/IncomingPaymentAttemptStatus.ts +20 -0
  171. package/src/objects/IncomingPaymentToAttemptsConnection.ts +39 -0
  172. package/src/objects/Invoice.ts +226 -0
  173. package/src/objects/InvoiceData.ts +185 -0
  174. package/src/objects/InvoiceType.ts +15 -0
  175. package/src/objects/LightningFeeEstimateForInvoiceInput.ts +28 -0
  176. package/src/objects/LightningFeeEstimateForNodeInput.ts +25 -0
  177. package/src/objects/LightningFeeEstimateOutput.ts +33 -0
  178. package/src/objects/LightningTransaction.ts +393 -0
  179. package/src/objects/LightsparkNode.ts +377 -0
  180. package/src/objects/LightsparkNodePurpose.ts +17 -0
  181. package/src/objects/LightsparkNodeStatus.ts +29 -0
  182. package/src/objects/LightsparkNodeToChannelsConnection.ts +50 -0
  183. package/src/objects/Node.ts +273 -0
  184. package/src/objects/NodeAddress.ts +29 -0
  185. package/src/objects/NodeAddressType.ts +18 -0
  186. package/src/objects/NodeToAddressesConnection.ts +39 -0
  187. package/src/objects/OnChainTransaction.ts +318 -0
  188. package/src/objects/OutgoingPayment.ts +319 -0
  189. package/src/objects/OutgoingPaymentAttempt.ts +164 -0
  190. package/src/objects/OutgoingPaymentAttemptStatus.ts +18 -0
  191. package/src/objects/OutgoingPaymentAttemptToHopsConnection.ts +37 -0
  192. package/src/objects/OutgoingPaymentToAttemptsConnection.ts +39 -0
  193. package/src/objects/PageInfo.ts +31 -0
  194. package/src/objects/PayInvoiceInput.ts +33 -0
  195. package/src/objects/PayInvoiceOutput.ts +22 -0
  196. package/src/objects/PaymentFailureReason.ts +29 -0
  197. package/src/objects/PaymentRequest.ts +231 -0
  198. package/src/objects/PaymentRequestData.ts +183 -0
  199. package/src/objects/PaymentRequestStatus.ts +15 -0
  200. package/src/objects/Permission.ts +39 -0
  201. package/src/objects/RequestWithdrawalInput.ts +35 -0
  202. package/src/objects/RequestWithdrawalOutput.ts +24 -0
  203. package/src/objects/RichText.ts +19 -0
  204. package/src/objects/RoutingTransaction.ts +150 -0
  205. package/src/objects/RoutingTransactionFailureReason.ts +17 -0
  206. package/src/objects/Secret.ts +23 -0
  207. package/src/objects/SendPaymentInput.ts +30 -0
  208. package/src/objects/SendPaymentOutput.ts +22 -0
  209. package/src/objects/Transaction.ts +609 -0
  210. package/src/objects/TransactionFailures.ts +23 -0
  211. package/src/objects/TransactionStatus.ts +23 -0
  212. package/src/objects/TransactionType.ts +31 -0
  213. package/src/objects/TransactionUpdate.ts +67 -0
  214. package/src/objects/WalletDashboard.ts +32 -0
  215. package/src/objects/WebhookEventType.ts +15 -0
  216. package/src/objects/Withdrawal.ts +144 -0
  217. package/src/objects/WithdrawalMode.ts +15 -0
  218. package/src/objects/WithdrawalRequest.ts +224 -0
  219. package/src/objects/WithdrawalRequestStatus.ts +17 -0
  220. package/src/objects/WithdrawalRequestToChannelClosingTransactionsConnection.ts +57 -0
  221. package/src/objects/WithdrawalRequestToChannelOpeningTransactionsConnection.ts +57 -0
  222. package/src/objects/index.ts +108 -0
  223. package/tsconfig.json +5 -0
package/src/client.ts ADDED
@@ -0,0 +1,759 @@
1
+ // Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
2
+
3
+ import { Query } from "@lightsparkdev/core";
4
+ import autoBind from "auto-bind";
5
+ import Observable from "zen-observable";
6
+
7
+ import {
8
+ AuthProvider,
9
+ b64encode,
10
+ decryptSecretWithNodePassword,
11
+ LightsparkAuthException,
12
+ LightsparkException,
13
+ LightsparkSigningException,
14
+ Maybe,
15
+ NodeKeyCache,
16
+ Requester,
17
+ StubAuthProvider,
18
+ } from "@lightsparkdev/core";
19
+ import { BitcoinFeeEstimate as BitcoinFeeEstimateQuery } from "./graphql/BitcoinFeeEstimate.js";
20
+ import { CreateApiToken } from "./graphql/CreateApiToken.js";
21
+ import { CreateInvoice } from "./graphql/CreateInvoice.js";
22
+ import { CreateNodeWalletAddress } from "./graphql/CreateNodeWalletAddress.js";
23
+ import { DecodeInvoice } from "./graphql/DecodeInvoice.js";
24
+ import { DeleteApiToken } from "./graphql/DeleteApiToken.js";
25
+ import { FundNode } from "./graphql/FundNode.js";
26
+ import { LightningFeeEstimateForInvoice } from "./graphql/LightningFeeEstimateForInvoice.js";
27
+ import { LightningFeeEstimateForNode } from "./graphql/LightningFeeEstimateForNode.js";
28
+ import {
29
+ AccountDashboard,
30
+ MultiNodeDashboard,
31
+ } from "./graphql/MultiNodeDashboard.js";
32
+ import { PayInvoice } from "./graphql/PayInvoice.js";
33
+ import { RecoverNodeSigningKey } from "./graphql/RecoverNodeSigningKey.js";
34
+ import { RequestWithdrawal } from "./graphql/RequestWithdrawal.js";
35
+ import { SendPayment } from "./graphql/SendPayment.js";
36
+ import { SingleNodeDashboard } from "./graphql/SingleNodeDashboard.js";
37
+ import { TransactionsForNode } from "./graphql/TransactionsForNode.js";
38
+ import { TransactionSubscription } from "./graphql/TransactionSubscription.js";
39
+ import Account from "./objects/Account.js";
40
+ import { ApiTokenFromJson } from "./objects/ApiToken.js";
41
+ import BitcoinNetwork from "./objects/BitcoinNetwork.js";
42
+ import CreateApiTokenOutput from "./objects/CreateApiTokenOutput.js";
43
+ import CurrencyAmount, {
44
+ CurrencyAmountFromJson,
45
+ } from "./objects/CurrencyAmount.js";
46
+ import FeeEstimate, { FeeEstimateFromJson } from "./objects/FeeEstimate.js";
47
+ import InvoiceData, { InvoiceDataFromJson } from "./objects/InvoiceData.js";
48
+ import InvoiceType from "./objects/InvoiceType.js";
49
+ import OutgoingPayment, {
50
+ OutgoingPaymentFromJson,
51
+ } from "./objects/OutgoingPayment.js";
52
+ import Permission from "./objects/Permission.js";
53
+ import Transaction, { TransactionFromJson } from "./objects/Transaction.js";
54
+ import TransactionUpdate, {
55
+ TransactionUpdateFromJson,
56
+ } from "./objects/TransactionUpdate.js";
57
+ import WalletDashboard from "./objects/WalletDashboard.js";
58
+ import WithdrawalMode from "./objects/WithdrawalMode.js";
59
+ import WithdrawalRequest, {
60
+ WithdrawalRequestFromJson,
61
+ } from "./objects/WithdrawalRequest.js";
62
+
63
+ /**
64
+ * The LightsparkClient is the main entrypoint for interacting with the Lightspark API.
65
+ *
66
+ * ```ts
67
+ * const lightsparkClient = new LightsparkClient(
68
+ * new AccountTokenAuthProvider(TOKEN_ID, TOKEN_SECRET)
69
+ * );
70
+ * const encodedInvoice = await lightsparkClient.createInvoice(
71
+ * RECEIVING_NODE_ID,
72
+ * { value: 100, unit: CurrencyUnit.SATOSHI },
73
+ * "Whasssupppp",
74
+ * InvoiceType.AMP,
75
+ * );
76
+ *
77
+ * const invoiceDetails = await lightsparkClient.decodeInvoice(encodedInvoice);
78
+ * console.log(invoiceDetails);
79
+ *
80
+ * const payment = await lightsparkClient.payInvoice(PAYING_NODE_ID, encodedInvoice, 1000);
81
+ * console.log(payment);
82
+ * ```
83
+ *
84
+ * @class LightsparkClient
85
+ */
86
+ class LightsparkClient {
87
+ private requester: Requester;
88
+
89
+ /**
90
+ * Constructs a new LightsparkClient.
91
+ *
92
+ * @param authProvider The auth provider to use for authentication. Defaults to a stub auth provider. For server-side
93
+ * use, you should use the `AccountTokenAuthProvider`.
94
+ * @param serverUrl The base URL of the server to connect to. Defaults to lightspark production.
95
+ * @param nodeKeyCache This is used to cache node keys for the duration of the session. Defaults to a new instance of
96
+ * `NodeKeyCache`. You should not need to change this.
97
+ */
98
+ constructor(
99
+ private authProvider: AuthProvider = new StubAuthProvider(),
100
+ private readonly serverUrl: string = "api.lightspark.com",
101
+ // TODO(Jeremy): Figure out a way to avoid needing this from the wallet client.
102
+ private readonly nodeKeyCache: NodeKeyCache = new NodeKeyCache()
103
+ ) {
104
+ this.requester = new Requester(
105
+ this.nodeKeyCache,
106
+ WALLET_SDK_ENDPOINT,
107
+ authProvider,
108
+ serverUrl
109
+ );
110
+
111
+ autoBind(this);
112
+ }
113
+
114
+ /**
115
+ * Sets the auth provider for the client. This is useful for switching between auth providers if you are using
116
+ * multiple accounts or waiting for the user to log in.
117
+ *
118
+ * @param authProvider
119
+ */
120
+ public async setAuthProvider(authProvider: AuthProvider) {
121
+ this.requester = new Requester(
122
+ this.nodeKeyCache,
123
+ WALLET_SDK_ENDPOINT,
124
+ authProvider,
125
+ this.serverUrl
126
+ );
127
+ this.authProvider = authProvider;
128
+ }
129
+
130
+ /**
131
+ * @returns Whether or not the client is authorized. This is useful for determining if the user is logged in or not.
132
+ */
133
+ public async isAuthorized(): Promise<boolean> {
134
+ return this.authProvider.isAuthorized();
135
+ }
136
+
137
+ /**
138
+ * @returns The current account, if one exists.
139
+ */
140
+ public async getCurrentAccount(): Promise<Maybe<Account>> {
141
+ return await this.requester.executeQuery<Account>(
142
+ Account.getAccountQuery()
143
+ );
144
+ }
145
+
146
+ /**
147
+ * Retrieves the most recent transactions for a given node.
148
+ *
149
+ * @param nodeId The node ID for which to read transactions
150
+ * @param numTransactions The maximum number of transactions to read. Defaults to 20.
151
+ * @param bitcoinNetwork The bitcoin network on which to read transactions. Defaults to MAINNET.
152
+ * @param afterDate Filters transactions to those after the given date. Defaults to undefined (no limit).
153
+ * @returns An array of transactions for the given node ID.
154
+ */
155
+ public async getRecentTransactions(
156
+ nodeId: string,
157
+ numTransactions: number = 20,
158
+ bitcoinNetwork: BitcoinNetwork = BitcoinNetwork.MAINNET,
159
+ afterDate: Maybe<string> = undefined
160
+ ): Promise<Transaction[]> {
161
+ const response = await this.requester.makeRawRequest(TransactionsForNode, {
162
+ nodeId,
163
+ network: bitcoinNetwork,
164
+ numTransactions,
165
+ afterDate,
166
+ });
167
+ return (
168
+ response.current_account?.recent_transactions.entities.map(
169
+ (transaction) => TransactionFromJson(transaction)
170
+ ) ?? []
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Starts listening for new transactions or updates to existing transactions for a list of nodes.
176
+ *
177
+ * @param nodeIds The node IDs for which to listen to transactions.
178
+ * @returns A zen-observable that emits transaction updates for the given node IDs.
179
+ */
180
+ public listenToTransactions(
181
+ nodeIds: string[]
182
+ ): Observable<TransactionUpdate | undefined> {
183
+ const response = this.requester.subscribe(TransactionSubscription, {
184
+ nodeIds,
185
+ });
186
+ return response.map(
187
+ (response) =>
188
+ response &&
189
+ response.data.transactions &&
190
+ TransactionUpdateFromJson(response.data.transactions)
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Retrieves a dashboard of basic info for the authenticated account. See `AccountDashboard` for which info is
196
+ * included.
197
+ *
198
+ * @param nodeIds The node IDs to include in the dashboard. Defaults to undefined (all nodes).
199
+ * @param bitcoinNetwork The bitcoin network to include in the dashboard. Defaults to MAINNET.
200
+ * @returns A basic account dashboard for the given node IDs.
201
+ * @throws LightsparkAuthException if the user is not logged in or a LightsparkException if no nodes are found.
202
+ */
203
+ public async getAccountDashboard(
204
+ nodeIds: string[] | undefined = undefined,
205
+ bitcoinNetwork: BitcoinNetwork = BitcoinNetwork.MAINNET
206
+ ): Promise<AccountDashboard> {
207
+ const response = await this.requester.makeRawRequest(MultiNodeDashboard, {
208
+ nodeIds: nodeIds,
209
+ network: bitcoinNetwork,
210
+ });
211
+ if (!response.current_account) {
212
+ throw new LightsparkAuthException("No current account");
213
+ }
214
+ if (
215
+ !response.current_account.dashboard_overview_nodes ||
216
+ response.current_account.dashboard_overview_nodes.entities.length === 0
217
+ ) {
218
+ throw new LightsparkException(
219
+ "NO_NODES_FOUND",
220
+ `No nodes found for this dashboard request. This could mean one of a few things:
221
+ 1. You are requesting MAINNET nodes, but you have no MAINNET nodes yet. In this case, request BitcoinNetwork.REGTEST instead.
222
+ 2. You are specifying specific node IDs, but those IDs don't exist or are not on the bitcoid network you requested.
223
+ 3. The api token or authentication mechanism you are using is not authorized to access the nodes you requested. If you're using
224
+ an API token, make sure it has the correct permissions for the desired network (only test tokens have access to REGTEST nodes).`
225
+ );
226
+ }
227
+ const account = response.current_account;
228
+ return {
229
+ id: account.id,
230
+ name: account.name,
231
+ nodes: account.dashboard_overview_nodes.entities.map((node) => {
232
+ return {
233
+ color: node.color,
234
+ displayName: node.display_name,
235
+ purpose: node.purpose,
236
+ id: node.id,
237
+ publicKey: node.public_key,
238
+ status: node.status,
239
+ addresses: {
240
+ count: node.addresses.count,
241
+ entities: node.addresses.entities.map((address) => {
242
+ return {
243
+ address: address.address,
244
+ type: address.type,
245
+ };
246
+ }),
247
+ },
248
+ localBalance:
249
+ node.local_balance && CurrencyAmountFromJson(node.local_balance),
250
+ remoteBalance:
251
+ node.remote_balance && CurrencyAmountFromJson(node.remote_balance),
252
+ blockchainBalance:
253
+ node.blockchain_balance &&
254
+ CurrencyAmountFromJson(node.blockchain_balance),
255
+ };
256
+ }),
257
+ blockchainBalance: !!account.blockchain_balance
258
+ ? {
259
+ l1Balance:
260
+ account.blockchain_balance.l1_balance &&
261
+ CurrencyAmountFromJson(account.blockchain_balance.l1_balance),
262
+ requiredReserve:
263
+ account.blockchain_balance.required_reserve &&
264
+ CurrencyAmountFromJson(
265
+ account.blockchain_balance.required_reserve
266
+ ),
267
+ availableBalance:
268
+ account.blockchain_balance.available_balance &&
269
+ CurrencyAmountFromJson(
270
+ account.blockchain_balance.available_balance
271
+ ),
272
+ unconfirmedBalance:
273
+ account.blockchain_balance.unconfirmed_balance &&
274
+ CurrencyAmountFromJson(
275
+ account.blockchain_balance.unconfirmed_balance
276
+ ),
277
+ }
278
+ : null,
279
+ localBalance:
280
+ account.local_balance && CurrencyAmountFromJson(account.local_balance),
281
+ remoteBalance:
282
+ account.remote_balance &&
283
+ CurrencyAmountFromJson(account.remote_balance),
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Gets a basic dashboard for a single node, including recent transactions. See `WalletDashboard` for which info is
289
+ * included.
290
+ *
291
+ * @param nodeId The node ID for which to get a dashboard.
292
+ * @param bitcoinNetwork The bitcoin network for which to get a dashboard. Defaults to MAINNET.
293
+ * @param transactionsAfterDate Filters recent transactions to those after the given date.
294
+ * Defaults to undefined (no limit).
295
+ * @returns A basic dashboard for the given node ID.
296
+ */
297
+ public async getSingleNodeDashboard(
298
+ nodeId: string,
299
+ bitcoinNetwork: BitcoinNetwork = BitcoinNetwork.MAINNET,
300
+ transactionsAfterDate: Maybe<string> = undefined
301
+ ): Promise<WalletDashboard> {
302
+ const response = await this.requester.makeRawRequest(SingleNodeDashboard, {
303
+ nodeId: nodeId,
304
+ network: bitcoinNetwork,
305
+ numTransactions: 20,
306
+ transactionsAfterDate,
307
+ });
308
+ if (!response.current_account) {
309
+ throw new LightsparkAuthException("No current account");
310
+ }
311
+ const account = response.current_account;
312
+ if (
313
+ !account.dashboard_overview_nodes ||
314
+ !account.dashboard_overview_nodes.entities ||
315
+ account.dashboard_overview_nodes.entities.length === 0
316
+ ) {
317
+ throw new LightsparkException(
318
+ "InvalidOrMissingNode",
319
+ "No nodes found for node dashboard"
320
+ );
321
+ }
322
+ const node = account.dashboard_overview_nodes.entities[0];
323
+ const nodeAddresses = node.addresses.entities.map((address) => {
324
+ return {
325
+ address: address.address,
326
+ type: address.type,
327
+ };
328
+ });
329
+ const currencyAmountOrUndefined = (json) => {
330
+ return json && CurrencyAmountFromJson(json);
331
+ };
332
+ return {
333
+ color: node.color,
334
+ displayName: account.name,
335
+ purpose: node.purpose,
336
+ id: node.id,
337
+ publicKey: node.public_key,
338
+ status: node.status,
339
+ addresses: nodeAddresses,
340
+ totalBalance: currencyAmountOrUndefined(node.total_balance),
341
+ totalLocalBalance: currencyAmountOrUndefined(node.total_local_balance),
342
+ onlineLocalBalance: currencyAmountOrUndefined(node.local_balance),
343
+ remoteBalance: currencyAmountOrUndefined(node.remote_balance),
344
+ blockchainBalance: node.blockchain_balance && {
345
+ availableBalance: currencyAmountOrUndefined(
346
+ node.blockchain_balance.available_balance
347
+ ),
348
+ confirmedBalance: currencyAmountOrUndefined(
349
+ node.blockchain_balance.confirmed_balance
350
+ ),
351
+ unconfirmedBalance: currencyAmountOrUndefined(
352
+ node.blockchain_balance.unconfirmed_balance
353
+ ),
354
+ totalBalance: currencyAmountOrUndefined(
355
+ node.blockchain_balance.total_balance
356
+ ),
357
+ },
358
+ recentTransactions:
359
+ account.recent_transactions?.entities.map((tx) => {
360
+ return TransactionFromJson(tx);
361
+ }) || [],
362
+ };
363
+ }
364
+
365
+ /**
366
+ * Creates an invoice for the given node.
367
+ *
368
+ * @param nodeId The node ID for which to create an invoice.
369
+ * @param amountMsats The amount of the invoice in msats. You can create a zero-amount invoice to accept any payment amount.
370
+ * @param memo A string memo to include in the invoice as a description.
371
+ * @param type The type of invoice to create. Defaults to a normal payment invoice, but you can pass InvoiceType.AMP
372
+ * to create an [AMP invoice](https://docs.lightning.engineering/lightning-network-tools/lnd/amp), which can be
373
+ * paid multiple times.
374
+ * @returns An encoded payment request for the invoice, or undefined if the invoice could not be created.
375
+ */
376
+ public async createInvoice(
377
+ nodeId: string,
378
+ amountMsats: number,
379
+ memo: string,
380
+ type: InvoiceType | undefined = undefined
381
+ ): Promise<string | undefined> {
382
+ const response = await this.requester.makeRawRequest(CreateInvoice, {
383
+ node_id: nodeId,
384
+ amount_msats: amountMsats,
385
+ memo,
386
+ type,
387
+ });
388
+ return response.create_invoice?.invoice.data?.encoded_payment_request;
389
+ }
390
+
391
+ /**
392
+ * Decodes an encoded lightning invoice string.
393
+ *
394
+ * @param encodedInvoice The string encoded invoice to decode.
395
+ * @returns Decoded invoice data.
396
+ */
397
+ public async decodeInvoice(encodedInvoice: string): Promise<InvoiceData> {
398
+ const response = await this.requester.makeRawRequest(DecodeInvoice, {
399
+ encoded_payment_request: encodedInvoice,
400
+ });
401
+ return InvoiceDataFromJson(response.decoded_payment_request);
402
+ }
403
+
404
+ /**
405
+ * Gets an estimate of the fee for sending a payment over the given bitcoin network.
406
+ *
407
+ * @param bitcoinNetwork The bitcoin network for which to get a fee estimate. Defaults to MAINNET.
408
+ * @returns A fee estimate for the given bitcoin network including a minimum fee rate, and a max-speed fee rate.
409
+ */
410
+ public async getBitcoinFeeEstimate(
411
+ bitcoinNetwork: BitcoinNetwork = BitcoinNetwork.MAINNET
412
+ ): Promise<FeeEstimate> {
413
+ const response = await this.requester.makeRawRequest(
414
+ BitcoinFeeEstimateQuery,
415
+ {
416
+ bitcoin_network: bitcoinNetwork,
417
+ }
418
+ );
419
+ return FeeEstimateFromJson(response.bitcoin_fee_estimate);
420
+ }
421
+
422
+ /**
423
+ * Gets an estimate of the fees that will be paid for a Lightning invoice.
424
+ *
425
+ * @param nodeId The node from where you want to send the payment.
426
+ * @param encodedPaymentRequest The invoice you want to pay (as defined by the BOLT11 standard).
427
+ * @param amountMsats If the invoice does not specify a payment amount, then the amount that you wish to pay,
428
+ * expressed in msats.
429
+ * @returns An estimate of the fees that will be paid for a Lightning invoice.
430
+ */
431
+ public async getLightningFeeEstimateForInvoice(
432
+ nodeId: string,
433
+ encodedPaymentRequest: string,
434
+ amountMsats: number | undefined = undefined
435
+ ): Promise<CurrencyAmount> {
436
+ const response = await this.requester.makeRawRequest(
437
+ LightningFeeEstimateForInvoice,
438
+ {
439
+ node_id: nodeId,
440
+ encoded_payment_request: encodedPaymentRequest,
441
+ amount_msats: amountMsats,
442
+ }
443
+ );
444
+ return CurrencyAmountFromJson(
445
+ response.lightning_fee_estimate_for_invoice.fee_estimate
446
+ );
447
+ }
448
+
449
+ /**
450
+ * Returns an estimate of the fees that will be paid to send a payment to another Lightning node.
451
+ *
452
+ * @param nodeId The node from where you want to send the payment.
453
+ * @param destinationNodePublicKey The public key of the node that you want to pay.
454
+ * @param amountMsats The payment amount expressed in msats.
455
+ * @returns An estimate of the fees that will be paid to send a payment to another Lightning node.
456
+ */
457
+ public async getLightningFeeEstimateForNode(
458
+ nodeId: string,
459
+ destinationNodePublicKey: string,
460
+ amountMsats: number
461
+ ): Promise<CurrencyAmount> {
462
+ const response = await this.requester.makeRawRequest(
463
+ LightningFeeEstimateForNode,
464
+ {
465
+ node_id: nodeId,
466
+ destination_node_public_key: destinationNodePublicKey,
467
+ amount_msats: amountMsats,
468
+ }
469
+ );
470
+ return CurrencyAmountFromJson(
471
+ response.lightning_fee_estimate_for_node.fee_estimate
472
+ );
473
+ }
474
+
475
+ /**
476
+ * Unlock the given node for sensitive operations like sending payments.
477
+ *
478
+ * @param nodeId The ID of the node to unlock.
479
+ * @param password The node password assigned at node creation.
480
+ * @returns True if the node was unlocked successfully, false otherwise.
481
+ */
482
+ public async unlockNode(nodeId: string, password: string): Promise<boolean> {
483
+ const encryptedKey = await this.recoverNodeSigningKey(nodeId);
484
+ if (!encryptedKey) {
485
+ console.warn("No encrypted key found for node " + nodeId);
486
+ return false;
487
+ }
488
+
489
+ const signingPrivateKey = await decryptSecretWithNodePassword(
490
+ encryptedKey.cipher,
491
+ encryptedKey.encrypted_value,
492
+ password
493
+ );
494
+
495
+ if (!signingPrivateKey) {
496
+ throw new LightsparkSigningException(
497
+ "Unable to decrypt signing key with provided password. Please try again."
498
+ );
499
+ }
500
+
501
+ let signingPrivateKeyPEM = "";
502
+ if (new Uint8Array(signingPrivateKey)[0] === 48) {
503
+ // Support DER format - https://github.com/lightsparkdev/webdev/pull/1982
504
+ signingPrivateKeyPEM = b64encode(signingPrivateKey);
505
+ } else {
506
+ const dec = new TextDecoder();
507
+ signingPrivateKeyPEM = dec.decode(signingPrivateKey);
508
+ }
509
+
510
+ await this.nodeKeyCache.loadKey(nodeId, signingPrivateKeyPEM);
511
+ return true;
512
+ }
513
+
514
+ private async recoverNodeSigningKey(
515
+ nodeId: string
516
+ ): Promise<Maybe<{ encrypted_value: string; cipher: string }>> {
517
+ const response = await this.requester.makeRawRequest(
518
+ RecoverNodeSigningKey,
519
+ { nodeId }
520
+ );
521
+ const nodeEntity = response.entity;
522
+ if (nodeEntity?.__typename === "LightsparkNode") {
523
+ return nodeEntity.encrypted_signing_private_key;
524
+ }
525
+ return null;
526
+ }
527
+
528
+ /**
529
+ * Directly unlocks a node with a signing private key.
530
+ *
531
+ * @param nodeId The ID of the node to unlock.
532
+ * @param signingPrivateKeyPEM The PEM-encoded signing private key.
533
+ */
534
+ public async loadNodeKey(nodeId: string, signingPrivateKeyPEM: string) {
535
+ await this.nodeKeyCache.loadKey(nodeId, signingPrivateKeyPEM);
536
+ }
537
+
538
+ /**
539
+ * Sends a lightning payment for a given invoice.
540
+ *
541
+ * @param payerNodeId The ID of the node that will pay the invoice.
542
+ * @param encodedInvoice The encoded invoice to pay.
543
+ * @param maximumFeesMsats Maximum fees (in msats) to pay for the payment. This parameter is required.
544
+ * As guidance, a maximum fee of 16 basis points should make almost all transactions succeed. For example,
545
+ * for a transaction between 10k sats and 100k sats, this would mean a fee limit of 16 to 160 sats.
546
+ * @param timeoutSecs A timeout for the payment in seconds. Defaults to 60 seconds.
547
+ * @param amountMsats The amount to pay in msats for a zero-amount invoice. Defaults to the full amount of the
548
+ * invoice. NOTE: This parameter can only be passed for a zero-amount invoice. Otherwise, the call will fail.
549
+ * @returns An `OutgoingPayment` object if the payment was successful, or undefined if the payment failed.
550
+ */
551
+ public async payInvoice(
552
+ payerNodeId: string,
553
+ encodedInvoice: string,
554
+ maximumFeesMsats: number,
555
+ timeoutSecs: number = 60,
556
+ amountMsats: number | undefined = undefined
557
+ ): Promise<OutgoingPayment | undefined> {
558
+ if (!this.nodeKeyCache.hasKey(payerNodeId)) {
559
+ throw new LightsparkSigningException("Paying node is not unlocked");
560
+ }
561
+ const variables: any = {
562
+ node_id: payerNodeId,
563
+ encoded_invoice: encodedInvoice,
564
+ timeout_secs: timeoutSecs,
565
+ maximum_fees_msats: maximumFeesMsats,
566
+ };
567
+ if (amountMsats !== undefined) {
568
+ variables.amount_msats = amountMsats;
569
+ }
570
+ const response = await this.requester.makeRawRequest(
571
+ PayInvoice,
572
+ variables,
573
+ payerNodeId
574
+ );
575
+ if (response.pay_invoice?.payment.outgoing_payment_failure_message) {
576
+ throw new LightsparkException(
577
+ "PaymentError",
578
+ response.pay_invoice?.payment.outgoing_payment_failure_message.rich_text_text
579
+ );
580
+ }
581
+ return (
582
+ response.pay_invoice &&
583
+ OutgoingPaymentFromJson(response.pay_invoice.payment)
584
+ );
585
+ }
586
+
587
+ /**
588
+ * Sends a payment directly to a node on the Lightning Network through the public key of the node without an invoice.
589
+ *
590
+ * @param payerNodeId The ID of the node that will send the payment.
591
+ * @param destinationPublicKey The public key of the destination node.
592
+ * @param timeoutSecs The timeout in seconds that we will try to make the payment.
593
+ * @param amountMsats The amount to pay in msats.
594
+ * @param maximumFeesMsats Maximum fees (in msats) to pay for the payment. This parameter is required.
595
+ * As guidance, a maximum fee of 15 basis points should make almost all transactions succeed. For example,
596
+ * for a transaction between 10k sats and 100k sats, this would mean a fee limit of 15 to 150 sats.
597
+ * @returns An `OutgoingPayment` object if the payment was successful, or undefined if the payment failed.
598
+ */
599
+ public async sendPayment(
600
+ payerNodeId: string,
601
+ destinationPublicKey: string,
602
+ timeoutSecs: number = 60,
603
+ amountMsats: number,
604
+ maximumFeesMsats: number
605
+ ): Promise<OutgoingPayment | undefined> {
606
+ if (!this.nodeKeyCache.hasKey(payerNodeId)) {
607
+ throw new LightsparkSigningException("Paying node is not unlocked");
608
+ }
609
+ const response = await this.requester.makeRawRequest(
610
+ SendPayment,
611
+ {
612
+ node_id: payerNodeId,
613
+ destination_public_key: destinationPublicKey,
614
+ timeout_secs: timeoutSecs,
615
+ amount_msats: amountMsats,
616
+ maximum_fees_msats: maximumFeesMsats,
617
+ },
618
+ payerNodeId
619
+ );
620
+ if (response.send_payment?.payment.outgoing_payment_failure_message) {
621
+ throw new LightsparkException(
622
+ "PaymentError",
623
+ response.send_payment?.payment.outgoing_payment_failure_message.rich_text_text
624
+ );
625
+ }
626
+ return (
627
+ response.send_payment &&
628
+ OutgoingPaymentFromJson(response.send_payment.payment)
629
+ );
630
+ }
631
+
632
+ /**
633
+ * Creates an L1 Bitcoin wallet address for a given node which can be used to deposit or withdraw funds.
634
+ *
635
+ * @param nodeId The ID of the node to create a wallet address for.
636
+ * @returns A string containing the wallet address for the given node.
637
+ */
638
+ public async createNodeWalletAddress(nodeId: string): Promise<string> {
639
+ const response = await this.requester.makeRawRequest(
640
+ CreateNodeWalletAddress,
641
+ { node_id: nodeId }
642
+ );
643
+ return response.create_node_wallet_address.wallet_address;
644
+ }
645
+
646
+ /**
647
+ * Withdraws funds from the account and sends it to the requested bitcoin address.
648
+ *
649
+ * Depending on the chosen mode, it will first take the funds from the wallet, and if applicable, close channels
650
+ * appropriately to recover enough funds and reopen channels with the remaining funds.
651
+ * The process is asynchronous and may take up to a few minutes. You can check the progress by polling the
652
+ * `WithdrawalRequest` that is created, or by subscribing to a webhook.
653
+ *
654
+ * @param nodeId The ID of the node from which to withdraw funds.
655
+ * @param amountSats The amount of funds to withdraw in satoshis.
656
+ * @param bitcoinAddress The Bitcoin address to withdraw funds to.
657
+ * @param mode The mode to use for the withdrawal. See `WithdrawalMode` for more information.
658
+ */
659
+ public async requestWithdrawal(
660
+ nodeId: string,
661
+ amountSats: number,
662
+ bitcoinAddress: string,
663
+ mode: WithdrawalMode
664
+ ): Promise<WithdrawalRequest> {
665
+ const response = await this.requester.makeRawRequest(
666
+ RequestWithdrawal,
667
+ {
668
+ node_id: nodeId,
669
+ amount_sats: amountSats,
670
+ bitcoin_address: bitcoinAddress,
671
+ withdrawal_mode: mode,
672
+ },
673
+ nodeId
674
+ );
675
+ return WithdrawalRequestFromJson(response.request_withdrawal.request);
676
+ }
677
+
678
+ /**
679
+ * Adds funds to a Lightspark node on the REGTEST network. If the amount is not specified, 10,000,000 SATOSHI will be
680
+ * added. This API only functions for nodes created on the REGTEST network and will return an error when called for
681
+ * any non-REGTEST node.
682
+ *
683
+ * @param nodeId The ID of the node to fund. Must be a REGTEST node.
684
+ * @param amountSats The amount of funds to add to the node in satoshis. Defaults to 10,000,000 SATOSHI.
685
+ * @returns
686
+ */
687
+ public async fundNode(
688
+ nodeId: string,
689
+ amountSats: number | undefined = undefined
690
+ ): Promise<CurrencyAmount> {
691
+ const response = await this.requester.makeRawRequest(FundNode, {
692
+ node_id: nodeId,
693
+ amount_sats: amountSats,
694
+ });
695
+ return CurrencyAmountFromJson(response.fund_node.amount);
696
+ }
697
+
698
+ /**
699
+ * Creates a new API token that can be used to authenticate requests for this account when using the Lightspark APIs
700
+ * and SDKs.
701
+ *
702
+ * @param name Creates a new API token that can be used to authenticate requests for this account when using the
703
+ * Lightspark APIs and SDKs.
704
+ * @param transact Whether the token should be able to transact or only view data.
705
+ * @param testMode True if the token should be able to access only testnet false to access only mainnet.
706
+ * @returns An object containing the API token and client secret.
707
+ */
708
+ public async createApiToken(
709
+ name: string,
710
+ transact: boolean = true,
711
+ testMode: boolean = true
712
+ ): Promise<CreateApiTokenOutput> {
713
+ let permissions: Permission[];
714
+ if (transact && testMode) {
715
+ permissions = [Permission.REGTEST_VIEW, Permission.REGTEST_TRANSACT];
716
+ } else if (transact && !testMode) {
717
+ permissions = [Permission.MAINNET_VIEW, Permission.MAINNET_TRANSACT];
718
+ } else if (!transact && testMode) {
719
+ permissions = [Permission.REGTEST_VIEW];
720
+ } else {
721
+ permissions = [Permission.MAINNET_VIEW];
722
+ }
723
+
724
+ const response = await this.requester.makeRawRequest(CreateApiToken, {
725
+ name,
726
+ permissions,
727
+ });
728
+ return {
729
+ apiToken: ApiTokenFromJson(response.create_api_token.api_token),
730
+ clientSecret: response.create_api_token.client_secret,
731
+ };
732
+ }
733
+
734
+ /**
735
+ * Deletes an existing API token from this account.
736
+ *
737
+ * @param id The ID of the API token to delete.
738
+ */
739
+ public async deleteApiToken(id: string): Promise<void> {
740
+ await this.requester.makeRawRequest(DeleteApiToken, { api_token_id: id });
741
+ }
742
+
743
+ /**
744
+ * Executes a raw `Query` against the Lightspark API.
745
+ *
746
+ * This generally should not be used directly, but is exposed for advanced use cases and for internal use to retrieve
747
+ * complex fields from objects.
748
+ *
749
+ * @param query The `Query` to execute.
750
+ * @returns The result of the query.
751
+ */
752
+ public executeRawQuery<T>(query: Query<T>): Promise<T | null> {
753
+ return this.requester.executeQuery(query);
754
+ }
755
+ }
756
+
757
+ const WALLET_SDK_ENDPOINT = "graphql/server/2023-04-04";
758
+
759
+ export default LightsparkClient;