@bsv/sdk 1.0.33 → 1.0.36

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 (133) hide show
  1. package/README.md +1 -3
  2. package/dist/cjs/mod.js +2 -0
  3. package/dist/cjs/mod.js.map +1 -1
  4. package/dist/cjs/package.json +1 -1
  5. package/dist/cjs/src/transaction/Transaction.js +5 -3
  6. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  7. package/dist/cjs/src/transaction/broadcasters/ARC.js +37 -25
  8. package/dist/cjs/src/transaction/broadcasters/ARC.js.map +1 -1
  9. package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js +12 -0
  10. package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -0
  11. package/dist/cjs/src/transaction/broadcasters/WhatsOnChainBroadcaster.js +66 -0
  12. package/dist/cjs/src/transaction/broadcasters/WhatsOnChainBroadcaster.js.map +1 -0
  13. package/dist/cjs/src/transaction/broadcasters/index.js +5 -5
  14. package/dist/cjs/src/transaction/broadcasters/index.js.map +1 -1
  15. package/dist/cjs/src/transaction/chaintrackers/DefaultChainTracker.js +12 -0
  16. package/dist/cjs/src/transaction/chaintrackers/DefaultChainTracker.js.map +1 -0
  17. package/dist/cjs/src/transaction/chaintrackers/WhatsOnChain.js +49 -0
  18. package/dist/cjs/src/transaction/chaintrackers/WhatsOnChain.js.map +1 -0
  19. package/dist/cjs/src/transaction/chaintrackers/index.js +11 -0
  20. package/dist/cjs/src/transaction/chaintrackers/index.js.map +1 -0
  21. package/dist/cjs/src/transaction/{broadcasters → http}/DefaultHttpClient.js +8 -4
  22. package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -0
  23. package/dist/cjs/src/transaction/http/FetchHttpClient.js +29 -0
  24. package/dist/cjs/src/transaction/http/FetchHttpClient.js.map +1 -0
  25. package/dist/cjs/src/transaction/http/HttpClient.js.map +1 -0
  26. package/dist/cjs/src/transaction/{broadcasters → http}/NodejsHttpClient.js +14 -12
  27. package/dist/cjs/src/transaction/http/NodejsHttpClient.js.map +1 -0
  28. package/dist/cjs/src/transaction/http/index.js +10 -0
  29. package/dist/cjs/src/transaction/http/index.js.map +1 -0
  30. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  31. package/dist/esm/mod.js +2 -0
  32. package/dist/esm/mod.js.map +1 -1
  33. package/dist/esm/src/transaction/Transaction.js +5 -3
  34. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  35. package/dist/esm/src/transaction/broadcasters/ARC.js +37 -25
  36. package/dist/esm/src/transaction/broadcasters/ARC.js.map +1 -1
  37. package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js +5 -0
  38. package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -0
  39. package/dist/esm/src/transaction/broadcasters/WhatsOnChainBroadcaster.js +65 -0
  40. package/dist/esm/src/transaction/broadcasters/WhatsOnChainBroadcaster.js.map +1 -0
  41. package/dist/esm/src/transaction/broadcasters/index.js +2 -2
  42. package/dist/esm/src/transaction/broadcasters/index.js.map +1 -1
  43. package/dist/esm/src/transaction/chaintrackers/DefaultChainTracker.js +5 -0
  44. package/dist/esm/src/transaction/chaintrackers/DefaultChainTracker.js.map +1 -0
  45. package/dist/esm/src/transaction/chaintrackers/WhatsOnChain.js +50 -0
  46. package/dist/esm/src/transaction/chaintrackers/WhatsOnChain.js.map +1 -0
  47. package/dist/esm/src/transaction/chaintrackers/index.js +3 -0
  48. package/dist/esm/src/transaction/chaintrackers/index.js.map +1 -0
  49. package/dist/esm/src/transaction/{broadcasters → http}/DefaultHttpClient.js +8 -5
  50. package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -0
  51. package/dist/esm/src/transaction/http/FetchHttpClient.js +26 -0
  52. package/dist/esm/src/transaction/http/FetchHttpClient.js.map +1 -0
  53. package/dist/esm/src/transaction/http/HttpClient.js.map +1 -0
  54. package/dist/esm/src/transaction/http/NodejsHttpClient.js +38 -0
  55. package/dist/esm/src/transaction/http/NodejsHttpClient.js.map +1 -0
  56. package/dist/esm/src/transaction/http/index.js +4 -0
  57. package/dist/esm/src/transaction/http/index.js.map +1 -0
  58. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  59. package/dist/types/mod.d.ts +2 -0
  60. package/dist/types/mod.d.ts.map +1 -1
  61. package/dist/types/src/transaction/Transaction.d.ts +3 -3
  62. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  63. package/dist/types/src/transaction/broadcasters/ARC.d.ts +23 -8
  64. package/dist/types/src/transaction/broadcasters/ARC.d.ts.map +1 -1
  65. package/dist/types/src/transaction/broadcasters/DefaultBroadcaster.d.ts +3 -0
  66. package/dist/types/src/transaction/broadcasters/DefaultBroadcaster.d.ts.map +1 -0
  67. package/dist/types/src/transaction/broadcasters/WhatsOnChainBroadcaster.d.ts +26 -0
  68. package/dist/types/src/transaction/broadcasters/WhatsOnChainBroadcaster.d.ts.map +1 -0
  69. package/dist/types/src/transaction/broadcasters/index.d.ts +3 -4
  70. package/dist/types/src/transaction/broadcasters/index.d.ts.map +1 -1
  71. package/dist/types/src/transaction/chaintrackers/DefaultChainTracker.d.ts +3 -0
  72. package/dist/types/src/transaction/chaintrackers/DefaultChainTracker.d.ts.map +1 -0
  73. package/dist/types/src/transaction/chaintrackers/WhatsOnChain.d.ts +28 -0
  74. package/dist/types/src/transaction/chaintrackers/WhatsOnChain.d.ts.map +1 -0
  75. package/dist/types/src/transaction/chaintrackers/index.d.ts +4 -0
  76. package/dist/types/src/transaction/chaintrackers/index.d.ts.map +1 -0
  77. package/dist/types/src/transaction/http/DefaultHttpClient.d.ts +8 -0
  78. package/dist/types/src/transaction/http/DefaultHttpClient.d.ts.map +1 -0
  79. package/dist/types/src/transaction/http/FetchHttpClient.d.ts +31 -0
  80. package/dist/types/src/transaction/http/FetchHttpClient.d.ts.map +1 -0
  81. package/dist/types/src/transaction/http/HttpClient.d.ts +43 -0
  82. package/dist/types/src/transaction/http/HttpClient.d.ts.map +1 -0
  83. package/dist/types/src/transaction/{broadcasters → http}/NodejsHttpClient.d.ts +2 -2
  84. package/dist/types/src/transaction/http/NodejsHttpClient.d.ts.map +1 -0
  85. package/dist/types/src/transaction/http/index.d.ts +7 -0
  86. package/dist/types/src/transaction/http/index.d.ts.map +1 -0
  87. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  88. package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +2 -0
  89. package/docs/examples/EXAMPLE_COMPLEX_TX.md +2 -4
  90. package/docs/examples/EXAMPLE_SIMPLE_TX.md +44 -5
  91. package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +29 -22
  92. package/docs/examples/EXAMPLE_VERIFYING_ROOTS.md +18 -63
  93. package/docs/examples/GETTING_STARTED_NODE_CJS.md +2 -4
  94. package/docs/examples/GETTING_STARTED_REACT.md +2 -4
  95. package/docs/primitives.md +61 -59
  96. package/docs/script.md +13 -11
  97. package/docs/transaction.md +489 -35
  98. package/mod.ts +3 -1
  99. package/package.json +21 -1
  100. package/src/transaction/Transaction.ts +5 -3
  101. package/src/transaction/__tests/Transaction.test.ts +62 -0
  102. package/src/transaction/broadcasters/ARC.ts +75 -27
  103. package/src/transaction/broadcasters/DefaultBroadcaster.ts +6 -0
  104. package/src/transaction/broadcasters/WhatsOnChainBroadcaster.ts +70 -0
  105. package/src/transaction/broadcasters/__tests/ARC.test.ts +92 -19
  106. package/src/transaction/broadcasters/__tests/WhatsOnChainBroadcaster.test.ts +165 -0
  107. package/src/transaction/broadcasters/index.ts +3 -4
  108. package/src/transaction/chaintrackers/DefaultChainTracker.ts +6 -0
  109. package/src/transaction/chaintrackers/WhatsOnChain.ts +70 -0
  110. package/src/transaction/chaintrackers/__tests/WhatsOnChainChainTracker.test.ts +135 -0
  111. package/src/transaction/chaintrackers/index.ts +3 -0
  112. package/src/transaction/http/DefaultHttpClient.ts +32 -0
  113. package/src/transaction/http/FetchHttpClient.ts +50 -0
  114. package/src/transaction/http/HttpClient.ts +45 -0
  115. package/src/transaction/http/NodejsHttpClient.ts +55 -0
  116. package/src/transaction/http/index.ts +6 -0
  117. package/dist/cjs/src/transaction/broadcasters/DefaultHttpClient.js.map +0 -1
  118. package/dist/cjs/src/transaction/broadcasters/HttpClient.js.map +0 -1
  119. package/dist/cjs/src/transaction/broadcasters/NodejsHttpClient.js.map +0 -1
  120. package/dist/esm/src/transaction/broadcasters/DefaultHttpClient.js.map +0 -1
  121. package/dist/esm/src/transaction/broadcasters/HttpClient.js.map +0 -1
  122. package/dist/esm/src/transaction/broadcasters/NodejsHttpClient.js +0 -36
  123. package/dist/esm/src/transaction/broadcasters/NodejsHttpClient.js.map +0 -1
  124. package/dist/types/src/transaction/broadcasters/DefaultHttpClient.d.ts +0 -6
  125. package/dist/types/src/transaction/broadcasters/DefaultHttpClient.d.ts.map +0 -1
  126. package/dist/types/src/transaction/broadcasters/HttpClient.d.ts +0 -33
  127. package/dist/types/src/transaction/broadcasters/HttpClient.d.ts.map +0 -1
  128. package/dist/types/src/transaction/broadcasters/NodejsHttpClient.d.ts.map +0 -1
  129. package/src/transaction/broadcasters/DefaultHttpClient.ts +0 -29
  130. package/src/transaction/broadcasters/HttpClient.ts +0 -34
  131. package/src/transaction/broadcasters/NodejsHttpClient.ts +0 -55
  132. /package/dist/cjs/src/transaction/{broadcasters → http}/HttpClient.js +0 -0
  133. /package/dist/esm/src/transaction/{broadcasters → http}/HttpClient.js +0 -0
@@ -0,0 +1,165 @@
1
+ import Transaction from '../../../../dist/cjs/src/transaction/Transaction.js'
2
+ import {NodejsHttpClient} from "../../../../dist/cjs/src/transaction/http/NodejsHttpClient.js";
3
+ import WhatsOnChainBroadcaster from "../../../../dist/cjs/src/transaction/broadcasters/WhatsOnChainBroadcaster.js";
4
+ import {FetchHttpClient} from "../../../../dist/cjs/src/transaction/http/FetchHttpClient.js";
5
+
6
+ // Mock Transaction
7
+ jest.mock('../../Transaction', () => {
8
+ return {
9
+ default: jest.fn().mockImplementation(() => {
10
+ return {
11
+ toHex: () => 'mocked_transaction_hex'
12
+ }
13
+ })
14
+ }
15
+ })
16
+
17
+ describe('WhatsOnChainBroadcaster', () => {
18
+ const network = 'main'
19
+ const successResponse = {
20
+ status: 200,
21
+ data: 'mocked_txid'
22
+ }
23
+
24
+ let transaction: Transaction
25
+
26
+ beforeEach(() => {
27
+ transaction = new Transaction()
28
+ })
29
+
30
+ it('should broadcast successfully using window.fetch', async () => {
31
+ // Mocking window.fetch
32
+ const mockFetch = mockedFetch(successResponse)
33
+ global.window = { fetch: mockFetch } as any
34
+
35
+ const broadcaster = new WhatsOnChainBroadcaster(network)
36
+ const response = await broadcaster.broadcast(transaction)
37
+
38
+ expect(mockFetch).toHaveBeenCalled()
39
+ expect(response).toEqual({
40
+ status: 'success',
41
+ txid: 'mocked_txid',
42
+ message: 'broadcast successful'
43
+ })
44
+ })
45
+
46
+ it('should broadcast successfully using Node.js https', async () => {
47
+ // Mocking Node.js https module
48
+ mockedHttps(successResponse)
49
+ delete global.window
50
+
51
+ const broadcaster = new WhatsOnChainBroadcaster(network)
52
+ const response = await broadcaster.broadcast(transaction)
53
+
54
+ expect(response).toEqual({
55
+ status: 'success',
56
+ txid: 'mocked_txid',
57
+ message: 'broadcast successful'
58
+ })
59
+ })
60
+
61
+ it('should broadcast successfully using provided fetch', async () => {
62
+
63
+ const mockFetch = mockedFetch(successResponse)
64
+
65
+ const broadcaster = new WhatsOnChainBroadcaster(network, new FetchHttpClient(mockFetch))
66
+ const response = await broadcaster.broadcast(transaction)
67
+
68
+ expect(mockFetch).toHaveBeenCalled()
69
+ expect(response).toEqual({
70
+ status: 'success',
71
+ txid: 'mocked_txid',
72
+ message: 'broadcast successful'
73
+ })
74
+ })
75
+
76
+ it('should broadcast successfully using provided https', async () => {
77
+
78
+ const mockHttps = mockedHttps(successResponse)
79
+ const broadcaster = new WhatsOnChainBroadcaster(network, new NodejsHttpClient(mockHttps))
80
+
81
+ const response = await broadcaster.broadcast(transaction)
82
+
83
+ expect(response).toEqual({
84
+ status: 'success',
85
+ txid: 'mocked_txid',
86
+ message: 'broadcast successful'
87
+ })
88
+ })
89
+
90
+ it('should handle network errors', async () => {
91
+ const mockFetch = jest.fn().mockRejectedValue(new Error('Network error'))
92
+ global.window = { fetch: mockFetch } as any
93
+
94
+ const broadcaster = new WhatsOnChainBroadcaster(network)
95
+ const response = await broadcaster.broadcast(transaction)
96
+
97
+ expect(mockFetch).toHaveBeenCalled()
98
+ expect(response).toEqual({
99
+ status: 'error',
100
+ code: '500',
101
+ description: 'Network error'
102
+ })
103
+ })
104
+
105
+ it('should handle non-200 responses', async () => {
106
+ const mockFetch = mockedFetch({
107
+ status: 400,
108
+ data: 'Bad request'
109
+ })
110
+ global.window = { fetch: mockFetch } as any
111
+
112
+ const broadcaster = new WhatsOnChainBroadcaster(network)
113
+ const response = await broadcaster.broadcast(transaction)
114
+
115
+ expect(mockFetch).toHaveBeenCalled()
116
+ expect(response).toEqual({
117
+ status: 'error',
118
+ code: '400',
119
+ description: 'Bad request'
120
+ })
121
+ })
122
+
123
+ function mockedFetch(response) {
124
+ return jest.fn().mockResolvedValue({
125
+ ok: response.status === 200,
126
+ status: response.status,
127
+ statusText: response.status === 200 ? 'OK' : 'Bad request',
128
+ headers: {
129
+ get(key: string) {
130
+ if (key === 'Content-Type') {
131
+ return 'text/plain'
132
+ }
133
+ }
134
+ },
135
+ text: async () => response.data
136
+ });
137
+ }
138
+
139
+ function mockedHttps(response) {
140
+ const https = {
141
+ request: (url, options, callback) => {
142
+ // eslint-disable-next-line
143
+ callback({
144
+ statusCode: response.status,
145
+ statusMessage: response.status == 200 ? 'OK' : 'Bad request',
146
+ headers: {
147
+ 'content-type': 'text/plain'
148
+ },
149
+ on: (event, handler) => {
150
+ if (event === 'data') handler(response.data)
151
+ if (event === 'end') handler()
152
+ }
153
+ })
154
+ return {
155
+ on: jest.fn(),
156
+ write: jest.fn(),
157
+ end: jest.fn()
158
+ }
159
+ }
160
+ }
161
+ jest.mock('https', () => https)
162
+ return https
163
+ }
164
+ })
165
+
@@ -1,5 +1,4 @@
1
1
  export { default as ARC } from './ARC.js'
2
- export type { HttpClient, HttpClientResponse, HttpClientRequestOptions } from './HttpClient.js'
3
- export { default as defaultHttpClient } from './DefaultHttpClient.js'
4
- export { NodejsHttpClient } from './NodejsHttpClient.js'
5
- export type { HttpsNodejs, NodejsHttpClientRequest } from './NodejsHttpClient.js'
2
+ export type { ArcConfig } from './ARC.js'
3
+ export { default as WhatsOnChainBroadcaster } from './WhatsOnChainBroadcaster.js'
4
+ export { defaultBroadcaster } from './DefaultBroadcaster.js'
@@ -0,0 +1,6 @@
1
+ import WhatsOnChain from "./WhatsOnChain.js";
2
+ import ChainTracker from "../ChainTracker.js";
3
+
4
+ export function defaultChainTracker(): ChainTracker {
5
+ return new WhatsOnChain()
6
+ }
@@ -0,0 +1,70 @@
1
+ import ChainTracker from "../ChainTracker.js";
2
+ import {HttpClient} from "../http/HttpClient.js";
3
+ import {defaultHttpClient} from "../http/DefaultHttpClient.js";
4
+
5
+ /** Configuration options for the WhatsOnChain ChainTracker. */
6
+ export interface WhatsOnChainConfig {
7
+ /** Authentication token for the WhatsOnChain API */
8
+ apiKey?: string
9
+ /** The HTTP client used to make requests to the API. */
10
+ httpClient?: HttpClient
11
+ }
12
+
13
+ interface WhatsOnChainBlockHeader {
14
+ merkleroot: string
15
+ }
16
+
17
+ /**
18
+ * Represents a chain tracker based on What's On Chain .
19
+ */
20
+ export default class WhatsOnChain implements ChainTracker {
21
+ readonly network: string
22
+ readonly apiKey: string
23
+ private readonly URL: string
24
+ private readonly httpClient: HttpClient
25
+
26
+ /**
27
+ * Constructs an instance of the WhatsOnChain ChainTracker.
28
+ *
29
+ * @param {'main' | 'test' | 'stn'} network - The BSV network to use when calling the WhatsOnChain API.
30
+ * @param {WhatsOnChainConfig} config - Configuration options for the WhatsOnChain ChainTracker.
31
+ */
32
+ constructor(network: 'main' | 'test' | 'stn' = 'main', config: WhatsOnChainConfig = {}) {
33
+ const {apiKey, httpClient} = config
34
+ this.network = network
35
+ this.URL = `https://api.whatsonchain.com/v1/bsv/${network}`
36
+ this.httpClient = httpClient ?? defaultHttpClient()
37
+ this.apiKey = apiKey
38
+ }
39
+
40
+ async isValidRootForHeight(root: string, height: number): Promise<boolean> {
41
+ const requestOptions = {
42
+ method: 'GET',
43
+ headers: this.getHeaders()
44
+ }
45
+
46
+ const response = await this.httpClient.request<WhatsOnChainBlockHeader>(`${this.URL}/block/${height}/header`, requestOptions)
47
+ if (response.ok) {
48
+ const { merkleroot} = response.data
49
+ return merkleroot === root
50
+ } else if (response.status === 404) {
51
+ return false
52
+ } else {
53
+ throw new Error(`Failed to verify merkleroot for height ${height} because of an error: ${JSON.stringify(response.data)} `)
54
+ }
55
+ }
56
+
57
+ private getHeaders() {
58
+ const headers: Record<string, string> = {
59
+ 'Accept': 'application/json',
60
+ }
61
+
62
+ if (this.apiKey) {
63
+ headers['Authorization'] = this.apiKey
64
+ }
65
+
66
+ return headers
67
+ }
68
+ }
69
+
70
+
@@ -0,0 +1,135 @@
1
+ import {NodejsHttpClient} from "../../../../dist/cjs/src/transaction/http/NodejsHttpClient.js";
2
+ import WhatsOnChain from "../../../../dist/cjs/src/transaction/chaintrackers/WhatsOnChain.js";
3
+ import {FetchHttpClient} from "../../../../dist/cjs/src/transaction/http/FetchHttpClient.js";
4
+
5
+
6
+ describe('WhatsOnChain ChainTracker', () => {
7
+ const network = 'main'
8
+ const height = 123456
9
+ const merkleroot = 'mocked_merkleroot'
10
+
11
+ const successResponse = {
12
+ status: 200,
13
+ data: {
14
+ merkleroot
15
+ }
16
+ }
17
+
18
+
19
+
20
+ it('should verify merkleroot successfully using window.fetch', async () => {
21
+ // Mocking window.fetch
22
+ const mockFetch = mockedFetch(successResponse)
23
+ global.window = { fetch: mockFetch } as any
24
+
25
+ const chainTracker = new WhatsOnChain(network)
26
+ const response = await chainTracker.isValidRootForHeight(merkleroot, height)
27
+
28
+ expect(mockFetch).toHaveBeenCalled()
29
+ expect(response).toEqual(true)
30
+ })
31
+
32
+ it('should verify merkleroot successfully using Node.js https', async () => {
33
+ // Mocking Node.js https module
34
+ mockedHttps(successResponse)
35
+ delete global.window
36
+
37
+ const chainTracker = new WhatsOnChain(network)
38
+ const response = await chainTracker.isValidRootForHeight(merkleroot, height)
39
+
40
+ expect(response).toEqual(true)
41
+ })
42
+
43
+ it('should verify merkleroot successfully using provided window.fetch', async () => {
44
+ const mockFetch = mockedFetch(successResponse)
45
+
46
+ const chainTracker = new WhatsOnChain(network, {httpClient: new FetchHttpClient(mockFetch)})
47
+ const response = await chainTracker.isValidRootForHeight(merkleroot, height)
48
+
49
+ expect(mockFetch).toHaveBeenCalled()
50
+ expect(response).toEqual(true)
51
+ })
52
+
53
+ it('should verify merkleroot successfully using provided Node.js https', async () => {
54
+ const mockHttps = mockedHttps(successResponse)
55
+
56
+ const chainTracker = new WhatsOnChain(network, {httpClient: new NodejsHttpClient(mockHttps)})
57
+ const response = await chainTracker.isValidRootForHeight(merkleroot, height)
58
+
59
+ expect(response).toEqual(true)
60
+ })
61
+
62
+ it('should respond with invalid root for height when block for height is not found', async () => {
63
+ const mockFetch = mockedFetch({
64
+ status: 404,
65
+ data: "not found"
66
+ })
67
+
68
+ const chainTracker = new WhatsOnChain(network, {httpClient: new FetchHttpClient(mockFetch)})
69
+ const response = await chainTracker.isValidRootForHeight(merkleroot, height)
70
+
71
+ expect(response).toEqual(false)
72
+ })
73
+
74
+ it('should handle network errors', async () => {
75
+ const mockFetch = jest.fn().mockRejectedValue(new Error('Network error'))
76
+
77
+ const chainTracker = new WhatsOnChain(network, {httpClient: new FetchHttpClient(mockFetch)})
78
+
79
+ await expect(chainTracker.isValidRootForHeight(merkleroot, height)).rejects.toThrow('Network error')
80
+ })
81
+
82
+ it('should throw error when received error response', async () => {
83
+ const mockFetch = mockedFetch({
84
+ status: 401,
85
+ data: { error: 'Unauthorized' }
86
+ })
87
+
88
+ const chainTracker = new WhatsOnChain(network, {httpClient: new FetchHttpClient(mockFetch)})
89
+
90
+ await expect(chainTracker.isValidRootForHeight(merkleroot, height)).rejects.toThrow(/Failed to verify merkleroot for height \d+ because of an error: .*/)
91
+ })
92
+
93
+ function mockedFetch(response) {
94
+ return jest.fn().mockResolvedValue({
95
+ ok: response.status === 200,
96
+ status: response.status,
97
+ statusText: response.status === 200 ? 'OK' : 'Bad request',
98
+ headers: {
99
+ get(key: string) {
100
+ if (key === 'Content-Type') {
101
+ return 'application/json'
102
+ }
103
+ }
104
+ },
105
+ json: async () => response.data
106
+ });
107
+ }
108
+
109
+ function mockedHttps(response) {
110
+ const https = {
111
+ request: (url, options, callback) => {
112
+ // eslint-disable-next-line
113
+ callback({
114
+ statusCode: response.status,
115
+ statusMessage: response.status == 200 ? 'OK' : 'Bad request',
116
+ headers: {
117
+ 'content-type': 'application/json'
118
+ },
119
+ on: (event, handler) => {
120
+ if (event === 'data') handler(JSON.stringify(response.data))
121
+ if (event === 'end') handler()
122
+ }
123
+ })
124
+ return {
125
+ on: jest.fn(),
126
+ write: jest.fn(),
127
+ end: jest.fn()
128
+ }
129
+ }
130
+ }
131
+ jest.mock('https', () => https)
132
+ return https
133
+ }
134
+ })
135
+
@@ -0,0 +1,3 @@
1
+ export { default as WhatsOnChain } from './WhatsOnChain.js'
2
+ export type { WhatsOnChainConfig } from './WhatsOnChain.js'
3
+ export { defaultChainTracker } from './DefaultChainTracker.js'
@@ -0,0 +1,32 @@
1
+ import { HttpClient, HttpClientResponse } from './HttpClient.js';
2
+ import { NodejsHttpClient } from './NodejsHttpClient.js';
3
+ import { FetchHttpClient } from './FetchHttpClient.js';
4
+
5
+ /**
6
+ * Returns a default HttpClient implementation based on the environment that it is run on.
7
+ * This method will attempt to use `window.fetch` if available (in browser environments).
8
+ * If running in a Node.js environment, it falls back to using the Node.js `https` module
9
+ */
10
+ export function defaultHttpClient(): HttpClient {
11
+ const noHttpClient: HttpClient = {
12
+ request(..._): Promise<HttpClientResponse> {
13
+ throw new Error('No method available to perform HTTP request');
14
+ },
15
+ };
16
+
17
+ if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
18
+ // Use fetch in a browser environment
19
+ return new FetchHttpClient(window.fetch);
20
+ } else if (typeof require !== 'undefined') {
21
+ // Use Node.js https module
22
+ // eslint-disable-next-line
23
+ try {
24
+ const https = require('https');
25
+ return new NodejsHttpClient(https);
26
+ } catch (e) {
27
+ return noHttpClient;
28
+ }
29
+ } else {
30
+ return noHttpClient;
31
+ }
32
+ }
@@ -0,0 +1,50 @@
1
+ import { HttpClient, HttpClientRequestOptions, HttpClientResponse } from './HttpClient.js';
2
+
3
+ /** fetch function interface limited to options needed by ts-sdk */
4
+ export interface Fetch {
5
+ /**
6
+ * Makes a request to the server.
7
+ * @param url The URL to make the request to.
8
+ * @param options The request configuration.
9
+ */
10
+ (url: string, options: FetchOptions): Promise<Response>;
11
+ }
12
+
13
+ /**
14
+ * An interface for configuration of the request to be passed to the fetch method
15
+ * limited to options needed by ts-sdk.
16
+ */
17
+ export interface FetchOptions {
18
+ /** A string to set request's method. */
19
+ method?: string;
20
+ /** An object literal set request's headers. */
21
+ headers?: Record<string, string>;
22
+ /** An object or null to set request's body. */
23
+ body?: string | null;
24
+ }
25
+
26
+ /**
27
+ * Adapter for Node.js Https module to be used as HttpClient
28
+ */
29
+ export class FetchHttpClient implements HttpClient {
30
+ constructor(private fetch: Fetch) {}
31
+
32
+ async request<D>(url: string, options: HttpClientRequestOptions): Promise<HttpClientResponse<D>> {
33
+ const fetchOptions: FetchOptions = {
34
+ method: options.method,
35
+ headers: options.headers,
36
+ body: JSON.stringify(options.data),
37
+ };
38
+
39
+ const res = await this.fetch(url, fetchOptions);
40
+ const mediaType = res.headers.get('Content-Type');
41
+ const data = mediaType === 'application/json' ? await res.json() : await res.text();
42
+
43
+ return {
44
+ ok: res.ok,
45
+ status: res.status,
46
+ statusText: res.statusText,
47
+ data: data as D,
48
+ };
49
+ }
50
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * An interface for HTTP client used to make HTTP requests.
3
+ */
4
+ export interface HttpClient {
5
+ /**
6
+ * Makes a request to the server.
7
+ * @param url The URL to make the request to.
8
+ * @param options The request configuration.
9
+ */
10
+ request<T = any, D = any>(url: string, options: HttpClientRequestOptions<D>): Promise<HttpClientResponse<T>>;
11
+ }
12
+
13
+ /**
14
+ * An interface for configuration of the request to be passed to the request method.
15
+ */
16
+ export interface HttpClientRequestOptions<Data = any> {
17
+ /** A string to set request's method. */
18
+ method?: string;
19
+ /** An object literal set request's headers. */
20
+ headers?: Record<string, string>;
21
+ /** An object or null to set request's body. */
22
+ data?: Data;
23
+ }
24
+
25
+ /**
26
+ * An interface for the response returned by the request method.
27
+ */
28
+ export type HttpClientResponse<T = any> = {
29
+ data: T;
30
+ /** The status code of the response. */
31
+ status: number;
32
+ /** The status text of the response. */
33
+ statusText: string;
34
+ /** A flag indicating whether the request ends with success status or not. */
35
+ ok: true;
36
+ } | {
37
+ data: any;
38
+ /** The status code of the response. */
39
+ status: number;
40
+ /** The status text of the response. */
41
+ statusText: string;
42
+ /** A flag indicating whether the request ends with success status or not. */
43
+ ok: false;
44
+ }
45
+
@@ -0,0 +1,55 @@
1
+ import { HttpClient, HttpClientRequestOptions, HttpClientResponse } from './HttpClient.js';
2
+
3
+ /** Node.js Https module interface limited to options needed by ts-sdk */
4
+ export interface HttpsNodejs {
5
+ request(url: string, options: HttpClientRequestOptions, callback: (res: any) => void): NodejsHttpClientRequest;
6
+ }
7
+
8
+ /** Nodejs result of the Node.js https.request call limited to options needed by ts-sdk */
9
+ export interface NodejsHttpClientRequest {
10
+ write(chunk: string): void;
11
+
12
+ end(): void;
13
+
14
+ on(event: string, callback: (data: any) => void): void;
15
+
16
+ end(): void;
17
+ }
18
+
19
+ /**
20
+ * Adapter for Node.js Https module to be used as HttpClient
21
+ */
22
+ export class NodejsHttpClient implements HttpClient {
23
+ constructor(private https: HttpsNodejs) {}
24
+
25
+ async request(url: string, requestOptions: HttpClientRequestOptions): Promise<HttpClientResponse> {
26
+ return await new Promise((resolve, reject) => {
27
+ const req = this.https.request(url, requestOptions, (res) => {
28
+ let body = '';
29
+ res.on('data', (chunk: string) => {
30
+ body += chunk;
31
+ });
32
+ res.on('end', () => {
33
+ const ok = res.statusCode >= 200 && res.statusCode <= 299;
34
+ const mediaType = res.headers['content-type'];
35
+ const data = body && mediaType === 'application/json' ? JSON.parse(body) : body;
36
+ resolve({
37
+ status: res.statusCode,
38
+ statusText: res.statusMessage,
39
+ ok,
40
+ data,
41
+ });
42
+ });
43
+ });
44
+
45
+ req.on('error', (error) => {
46
+ reject(error);
47
+ });
48
+
49
+ if (!!requestOptions.data) {
50
+ req.write(JSON.stringify(requestOptions.data));
51
+ }
52
+ req.end();
53
+ });
54
+ }
55
+ }
@@ -0,0 +1,6 @@
1
+ export type { HttpClient, HttpClientResponse, HttpClientRequestOptions } from './HttpClient.js';
2
+ export { defaultHttpClient } from './DefaultHttpClient.js';
3
+ export { NodejsHttpClient } from './NodejsHttpClient.js';
4
+ export { FetchHttpClient } from './FetchHttpClient.js';
5
+ export type { Fetch, FetchOptions } from './FetchHttpClient.js';
6
+ export type { HttpsNodejs, NodejsHttpClientRequest } from './NodejsHttpClient.js';
@@ -1 +0,0 @@
1
- {"version":3,"file":"DefaultHttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/DefaultHttpClient.ts"],"names":[],"mappings":";;AACA,+DAAuD;AAEvD;;GAEG;AACH,SAAwB,iBAAiB;IACrC,MAAM,YAAY,GAAc;QAC5B,KAAK,CAAC,GAAG,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;QAClE,CAAC;KACJ,CAAA;IAED,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE;QACrE,qCAAqC;QACrC,OAAO,MAAM,CAAA;KAChB;SAAM,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE;QACvC,2BAA2B;QAC3B,2BAA2B;QAC3B,IAAI;YACA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC9B,OAAO,IAAI,sCAAgB,CAAC,KAAK,CAAC,CAAA;SACrC;QAAC,OAAO,CAAC,EAAE;YACR,OAAO,YAAY,CAAA;SACtB;KACJ;SAAM;QACH,OAAO,YAAY,CAAA;KACtB;AACL,CAAC;AAtBD,oCAsBC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/HttpClient.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"NodejsHttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/NodejsHttpClient.ts"],"names":[],"mappings":";;;AAkBA;;GAEG;AACH,MAAa,gBAAgB;IACzB,YAAoB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IACtC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,cAAwC;QAC7D,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE;gBACtD,IAAI,IAAI,GAAG,EAAE,CAAA;gBACb,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;oBAC7B,IAAI,IAAI,KAAK,CAAA;gBACjB,CAAC,CAAC,CAAA;gBACF,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACf,OAAO,CAAC;wBACJ,EAAE,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG;wBAClD,UAAU,EAAE,GAAG,CAAC,UAAU;wBAC1B,KAAK,CAAC,IAAI;4BACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;wBAC3B,CAAC;qBACJ,CAAC,CAAA;gBACN,CAAC,CAAC,CAAA;YACN,CAAC,CAAC,CAAA;YAEF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;gBACpB,MAAM,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE;gBACvB,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;aACjC;YACD,GAAG,CAAC,GAAG,EAAE,CAAA;QACb,CAAC,CAAC,CAAA;IACN,CAAC;CACJ;AAhCD,4CAgCC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"DefaultHttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/DefaultHttpClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAEvD;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB;IACrC,MAAM,YAAY,GAAc;QAC5B,KAAK,CAAC,GAAG,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;QAClE,CAAC;KACJ,CAAA;IAED,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE;QACrE,qCAAqC;QACrC,OAAO,MAAM,CAAA;KAChB;SAAM,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE;QACvC,2BAA2B;QAC3B,2BAA2B;QAC3B,IAAI;YACA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC9B,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAA;SACrC;QAAC,OAAO,CAAC,EAAE;YACR,OAAO,YAAY,CAAA;SACtB;KACJ;SAAM;QACH,OAAO,YAAY,CAAA;KACtB;AACL,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/HttpClient.ts"],"names":[],"mappings":""}
@@ -1,36 +0,0 @@
1
- /**
2
- * Adapter for Node.js Https module to be used as HttpClient
3
- */
4
- export class NodejsHttpClient {
5
- https;
6
- constructor(https) {
7
- this.https = https;
8
- }
9
- async fetch(url, requestOptions) {
10
- return await new Promise((resolve, reject) => {
11
- const req = this.https.request(url, requestOptions, res => {
12
- let data = '';
13
- res.on('data', (chunk) => {
14
- data += chunk;
15
- });
16
- res.on('end', () => {
17
- resolve({
18
- ok: res.statusCode >= 200 && res.statusCode <= 299,
19
- statusCode: res.statusCode,
20
- async json() {
21
- return JSON.parse(data);
22
- }
23
- });
24
- });
25
- });
26
- req.on('error', error => {
27
- reject(error);
28
- });
29
- if (!!requestOptions.body) {
30
- req.write(requestOptions.body);
31
- }
32
- req.end();
33
- });
34
- }
35
- }
36
- //# sourceMappingURL=NodejsHttpClient.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NodejsHttpClient.js","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/NodejsHttpClient.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACL;IAApB,YAAoB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IACtC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,cAAwC;QAC7D,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE;gBACtD,IAAI,IAAI,GAAG,EAAE,CAAA;gBACb,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;oBAC7B,IAAI,IAAI,KAAK,CAAA;gBACjB,CAAC,CAAC,CAAA;gBACF,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACf,OAAO,CAAC;wBACJ,EAAE,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG;wBAClD,UAAU,EAAE,GAAG,CAAC,UAAU;wBAC1B,KAAK,CAAC,IAAI;4BACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;wBAC3B,CAAC;qBACJ,CAAC,CAAA;gBACN,CAAC,CAAC,CAAA;YACN,CAAC,CAAC,CAAA;YAEF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;gBACpB,MAAM,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE;gBACvB,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;aACjC;YACD,GAAG,CAAC,GAAG,EAAE,CAAA;QACb,CAAC,CAAC,CAAA;IACN,CAAC;CACJ"}
@@ -1,6 +0,0 @@
1
- import { HttpClient } from "./HttpClient.js";
2
- /**
3
- * Returns a default HttpClient implementation based on the environment that it is run on.
4
- */
5
- export default function defaultHttpClient(): HttpClient;
6
- //# sourceMappingURL=DefaultHttpClient.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DefaultHttpClient.d.ts","sourceRoot":"","sources":["../../../../../src/transaction/broadcasters/DefaultHttpClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAqB,MAAM,iBAAiB,CAAC;AAG/D;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,IAAI,UAAU,CAsBtD"}