@ardrive/turbo-sdk 1.25.0 → 1.26.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.
Files changed (48) hide show
  1. package/README.md +170 -62
  2. package/bundles/web.bundle.min.js +1584 -730
  3. package/lib/cjs/common/events.js +256 -0
  4. package/lib/cjs/common/events.test.js +470 -0
  5. package/lib/cjs/common/http.js +4 -13
  6. package/lib/cjs/common/turbo.js +6 -4
  7. package/lib/cjs/common/upload.js +65 -37
  8. package/lib/cjs/node/signer.js +30 -11
  9. package/lib/cjs/node/upload.js +7 -1
  10. package/lib/cjs/utils/axiosClient.js +3 -0
  11. package/lib/cjs/utils/readableStream.js +15 -0
  12. package/lib/cjs/version.js +1 -1
  13. package/lib/cjs/web/signer.js +55 -28
  14. package/lib/esm/common/events.js +249 -0
  15. package/lib/esm/common/events.test.js +468 -0
  16. package/lib/esm/common/http.js +4 -13
  17. package/lib/esm/common/turbo.js +6 -4
  18. package/lib/esm/common/upload.js +66 -38
  19. package/lib/esm/node/signer.js +30 -11
  20. package/lib/esm/node/upload.js +7 -1
  21. package/lib/esm/utils/axiosClient.js +3 -0
  22. package/lib/esm/utils/readableStream.js +15 -0
  23. package/lib/esm/version.js +1 -1
  24. package/lib/esm/web/signer.js +55 -28
  25. package/lib/types/common/events.d.ts +56 -0
  26. package/lib/types/common/events.d.ts.map +1 -0
  27. package/lib/types/common/events.test.d.ts +2 -0
  28. package/lib/types/common/events.test.d.ts.map +1 -0
  29. package/lib/types/common/http.d.ts +1 -2
  30. package/lib/types/common/http.d.ts.map +1 -1
  31. package/lib/types/common/signer.d.ts +1 -1
  32. package/lib/types/common/signer.d.ts.map +1 -1
  33. package/lib/types/common/turbo.d.ts +4 -4
  34. package/lib/types/common/turbo.d.ts.map +1 -1
  35. package/lib/types/common/upload.d.ts +13 -5
  36. package/lib/types/common/upload.d.ts.map +1 -1
  37. package/lib/types/node/signer.d.ts +1 -1
  38. package/lib/types/node/signer.d.ts.map +1 -1
  39. package/lib/types/node/upload.d.ts.map +1 -1
  40. package/lib/types/types.d.ts +61 -7
  41. package/lib/types/types.d.ts.map +1 -1
  42. package/lib/types/utils/axiosClient.d.ts.map +1 -1
  43. package/lib/types/utils/readableStream.d.ts +0 -1
  44. package/lib/types/utils/readableStream.d.ts.map +1 -1
  45. package/lib/types/version.d.ts +1 -1
  46. package/lib/types/web/signer.d.ts +1 -1
  47. package/lib/types/web/signer.d.ts.map +1 -1
  48. package/package.json +9 -7
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TurboEventEmitter = void 0;
4
+ exports.createStreamWithEvents = createStreamWithEvents;
5
+ exports.createStreamWithUploadEvents = createStreamWithUploadEvents;
6
+ exports.createStreamWithSigningEvents = createStreamWithSigningEvents;
7
+ /**
8
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ const eventemitter3_1 = require("eventemitter3");
23
+ const stream_1 = require("stream");
24
+ /**
25
+ * Creates a ReadableStream with events that emits progress and error events using the event names map.
26
+ *
27
+ * E.g.
28
+ *
29
+ * ```ts
30
+ * const eventNamesMap = {
31
+ * 'on-progress': 'signing-progress', // emits 'signing-progress' on event progress
32
+ * 'on-error': 'signing-error', // emits 'signing-error' errors
33
+ * 'on-end': 'signing-success', // emits 'signing-success' on end
34
+ * };
35
+ *
36
+ * const streamWithEvents = createStreamWithEvents({
37
+ * data,
38
+ * dataSize,
39
+ * emitter,
40
+ * eventNamesMap,
41
+ * });
42
+ * ```
43
+ */
44
+ function createReadableStreamWithEvents({ data, dataSize, emitter, eventNamesMap, }) {
45
+ const originalStream = data instanceof ReadableStream
46
+ ? data
47
+ : new ReadableStream({
48
+ start: (controller) => {
49
+ controller.enqueue(data);
50
+ controller.close();
51
+ },
52
+ });
53
+ let processedBytes = 0;
54
+ let reader;
55
+ const stream = new ReadableStream({
56
+ start() {
57
+ reader = originalStream.getReader();
58
+ },
59
+ async pull(controller) {
60
+ try {
61
+ const { value, done } = await reader.read();
62
+ if (done) {
63
+ emitter.emit(eventNamesMap['on-end']);
64
+ controller.close();
65
+ return;
66
+ }
67
+ processedBytes += value.length;
68
+ emitter.emit(eventNamesMap['on-progress'], {
69
+ processedBytes,
70
+ totalBytes: dataSize,
71
+ });
72
+ controller.enqueue(value);
73
+ }
74
+ catch (error) {
75
+ emitter.emit(eventNamesMap['on-error'], error);
76
+ controller.error(error);
77
+ }
78
+ },
79
+ cancel(reason) {
80
+ return reader.cancel(reason);
81
+ },
82
+ });
83
+ return {
84
+ stream,
85
+ resume: () => void 0, // not needed for ReadableStreams but stubbed out for type compatibility
86
+ };
87
+ }
88
+ /**
89
+ * Creates an eventing Readable stream that emits progress and error events.
90
+ *
91
+ * NOTE: When dealing ith Readable streams, any downstream consumer stream will need to call `resume()` once the consumer is properly set up.
92
+ * If we were to call it internally here, bytes would start flowing due to the configured 'data' event listener.
93
+ * For ReadableStreams, this is not a concern, so we stub out the resume function
94
+ *
95
+ * Example usage:
96
+ *
97
+ * ```ts
98
+ * const { stream, resume } = createReadableWithEvents({
99
+ * data,
100
+ * dataSize,
101
+ * emitter,
102
+ * eventNamesMap,
103
+ * });
104
+ *
105
+ * // setup any promise that will consume the stream (e.g. a POST request)
106
+ * const promise = new Promise((resolve, reject) => {
107
+ * stream.on('data', (chunk) => {
108
+ * resolve(chunk);
109
+ * });
110
+ * });
111
+ *
112
+ * // allow bytes to start flowing so the promise gets the data
113
+ * resume();
114
+ *
115
+ * // wait for the promise to resolve
116
+ * const result = await promise;
117
+ * ```
118
+ */
119
+ function createReadableWithEvents({ data, dataSize, emitter, eventNamesMap, }) {
120
+ const existingStream = data instanceof stream_1.Readable ? data : stream_1.Readable.from(data);
121
+ const eventingStream = new stream_1.PassThrough();
122
+ // pause the stream to avoid emitting progress events until the stream is ready
123
+ existingStream.pause();
124
+ // add listener to emit progress events as the stream is read
125
+ let processedBytes = 0;
126
+ existingStream.on('data', (chunk) => {
127
+ eventingStream.write(chunk);
128
+ processedBytes += chunk.length;
129
+ emitter.emit(eventNamesMap['on-progress'], {
130
+ processedBytes,
131
+ totalBytes: dataSize,
132
+ });
133
+ });
134
+ existingStream.on('end', () => {
135
+ emitter.emit(eventNamesMap['on-end']);
136
+ eventingStream.end();
137
+ });
138
+ existingStream.on('error', (error) => {
139
+ emitter.emit(eventNamesMap['on-error'], error);
140
+ eventingStream.destroy(error);
141
+ });
142
+ return {
143
+ stream: eventingStream,
144
+ // allows bytes to start flowing from the original stream when the consumer is ready
145
+ resume: () => existingStream.resume(),
146
+ };
147
+ }
148
+ /**
149
+ * Creates an eventing stream from the input data that emits progress and error events
150
+ */
151
+ function createStreamWithEvents({ data, dataSize, emitter, eventNamesMap, }) {
152
+ if (data instanceof ReadableStream ||
153
+ (typeof window !== 'undefined' && data instanceof Buffer)) {
154
+ return createReadableStreamWithEvents({
155
+ data,
156
+ dataSize,
157
+ emitter,
158
+ eventNamesMap,
159
+ });
160
+ }
161
+ if (data instanceof stream_1.Readable || data instanceof Buffer) {
162
+ return createReadableWithEvents({
163
+ data,
164
+ dataSize,
165
+ emitter,
166
+ eventNamesMap,
167
+ });
168
+ }
169
+ throw new Error('Invalid data or platform type');
170
+ }
171
+ class TurboEventEmitter extends eventemitter3_1.EventEmitter {
172
+ constructor({ onProgress, onError, onSuccess, onUploadProgress, onUploadError, onUploadSuccess, onSigningProgress, onSigningError, onSigningSuccess, } = {}) {
173
+ super();
174
+ if (onUploadProgress !== undefined) {
175
+ this.on('upload-progress', onUploadProgress);
176
+ }
177
+ if (onUploadError !== undefined) {
178
+ this.on('upload-error', onUploadError);
179
+ }
180
+ if (onUploadSuccess !== undefined) {
181
+ this.on('upload-success', onUploadSuccess);
182
+ }
183
+ if (onSigningProgress !== undefined) {
184
+ this.on('signing-progress', onSigningProgress);
185
+ }
186
+ if (onSigningError !== undefined) {
187
+ this.on('signing-error', onSigningError);
188
+ }
189
+ if (onSigningSuccess !== undefined) {
190
+ this.on('signing-success', onSigningSuccess);
191
+ }
192
+ if (onProgress !== undefined) {
193
+ this.on('overall-progress', onProgress);
194
+ }
195
+ if (onError !== undefined) {
196
+ this.on('overall-error', onError);
197
+ }
198
+ if (onSuccess !== undefined) {
199
+ this.on('overall-success', onSuccess);
200
+ }
201
+ // emit listeners for total events
202
+ this.on('signing-progress', (event) => {
203
+ this.emit('overall-progress', {
204
+ ...event,
205
+ processedBytes: event.processedBytes / 2, // since the total progress requires 2 passes through the stream, signing progress is only half of the total progress
206
+ totalBytes: event.totalBytes,
207
+ step: 'signing',
208
+ });
209
+ });
210
+ this.on('signing-error', (error) => {
211
+ this.emit('overall-error', error);
212
+ });
213
+ this.on('upload-progress', (event) => {
214
+ this.emit('overall-progress', {
215
+ ...event,
216
+ processedBytes: event.totalBytes / 2 + event.processedBytes / 2, // Start at 50% since signing is done, then add half of upload progress
217
+ totalBytes: event.totalBytes,
218
+ step: 'upload',
219
+ });
220
+ });
221
+ this.on('upload-error', (error) => {
222
+ this.emit('overall-error', error);
223
+ });
224
+ // NOTE: this is the last event emitted for successful upload,
225
+ // if another step was added (e.g. verifying optimistic caching)
226
+ // then this overall-success event will be emitted after that step
227
+ this.on('upload-success', () => {
228
+ this.emit('overall-success');
229
+ });
230
+ }
231
+ }
232
+ exports.TurboEventEmitter = TurboEventEmitter;
233
+ function createStreamWithUploadEvents({ data, dataSize, emitter = new TurboEventEmitter(), }) {
234
+ return createStreamWithEvents({
235
+ data,
236
+ dataSize,
237
+ emitter,
238
+ eventNamesMap: {
239
+ 'on-progress': 'upload-progress',
240
+ 'on-error': 'upload-error',
241
+ 'on-end': 'upload-success',
242
+ },
243
+ });
244
+ }
245
+ function createStreamWithSigningEvents({ data, dataSize, emitter = new TurboEventEmitter(), }) {
246
+ return createStreamWithEvents({
247
+ data,
248
+ dataSize,
249
+ emitter,
250
+ eventNamesMap: {
251
+ 'on-progress': 'signing-progress',
252
+ 'on-error': 'signing-error',
253
+ 'on-end': 'signing-success',
254
+ },
255
+ });
256
+ }