react-native-buffered-blob 1.0.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/android/AGENTS.md +74 -0
- package/android/build.gradle +34 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/bufferedblob/BufferedBlobModule.kt +274 -0
- package/android/src/main/java/com/bufferedblob/BufferedBlobPackage.kt +32 -0
- package/android/src/main/java/com/bufferedblob/HandleRegistry.kt +84 -0
- package/android/src/main/java/com/bufferedblob/StreamingBridge.kt +211 -0
- package/cpp/AGENTS.md +71 -0
- package/cpp/AndroidPlatformBridge.cpp +437 -0
- package/cpp/AndroidPlatformBridge.h +79 -0
- package/cpp/BufferedBlobStreamingHostObject.cpp +344 -0
- package/cpp/BufferedBlobStreamingHostObject.h +118 -0
- package/cpp/CMakeLists.txt +49 -0
- package/cpp/jni_onload.cpp +32 -0
- package/ios/AGENTS.md +76 -0
- package/ios/BufferedBlobModule.h +44 -0
- package/ios/BufferedBlobModule.m +433 -0
- package/ios/BufferedBlobModule.mm +192 -0
- package/ios/BufferedBlobStreamingBridge.h +21 -0
- package/ios/BufferedBlobStreamingBridge.mm +442 -0
- package/ios/HandleRegistry.h +29 -0
- package/ios/HandleRegistry.m +67 -0
- package/ios/HandleTypes.h +83 -0
- package/ios/HandleTypes.m +333 -0
- package/lib/module/AGENTS.md +70 -0
- package/lib/module/NativeBufferedBlob.js +5 -0
- package/lib/module/NativeBufferedBlob.js.map +1 -0
- package/lib/module/api/AGENTS.md +62 -0
- package/lib/module/api/download.js +40 -0
- package/lib/module/api/download.js.map +1 -0
- package/lib/module/api/fileOps.js +70 -0
- package/lib/module/api/fileOps.js.map +1 -0
- package/lib/module/api/hash.js +13 -0
- package/lib/module/api/hash.js.map +1 -0
- package/lib/module/api/readFile.js +23 -0
- package/lib/module/api/readFile.js.map +1 -0
- package/lib/module/api/writeFile.js +18 -0
- package/lib/module/api/writeFile.js.map +1 -0
- package/lib/module/errors.js +45 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/index.js +25 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/module.js +19 -0
- package/lib/module/module.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/paths.js +32 -0
- package/lib/module/paths.js.map +1 -0
- package/lib/module/types.js +15 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/wrappers.js +107 -0
- package/lib/module/wrappers.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeBufferedBlob.d.ts +37 -0
- package/lib/typescript/src/NativeBufferedBlob.d.ts.map +1 -0
- package/lib/typescript/src/api/download.d.ts +13 -0
- package/lib/typescript/src/api/download.d.ts.map +1 -0
- package/lib/typescript/src/api/fileOps.d.ts +9 -0
- package/lib/typescript/src/api/fileOps.d.ts.map +1 -0
- package/lib/typescript/src/api/hash.d.ts +3 -0
- package/lib/typescript/src/api/hash.d.ts.map +1 -0
- package/lib/typescript/src/api/readFile.d.ts +3 -0
- package/lib/typescript/src/api/readFile.d.ts.map +1 -0
- package/lib/typescript/src/api/writeFile.d.ts +3 -0
- package/lib/typescript/src/api/writeFile.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +25 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +11 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/module.d.ts +23 -0
- package/lib/typescript/src/module.d.ts.map +1 -0
- package/lib/typescript/src/paths.d.ts +11 -0
- package/lib/typescript/src/paths.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +37 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/wrappers.d.ts +14 -0
- package/lib/typescript/src/wrappers.d.ts.map +1 -0
- package/package.json +114 -0
- package/react-native-buffered-blob.podspec +37 -0
- package/react-native.config.js +10 -0
- package/src/AGENTS.md +70 -0
- package/src/NativeBufferedBlob.ts +54 -0
- package/src/api/AGENTS.md +62 -0
- package/src/api/download.ts +46 -0
- package/src/api/fileOps.ts +83 -0
- package/src/api/hash.ts +14 -0
- package/src/api/readFile.ts +37 -0
- package/src/api/writeFile.ts +24 -0
- package/src/errors.ts +50 -0
- package/src/index.ts +28 -0
- package/src/module.ts +48 -0
- package/src/paths.ts +35 -0
- package/src/types.ts +42 -0
- package/src/wrappers.ts +123 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#import "HandleTypes.h"
|
|
2
|
+
|
|
3
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
4
|
+
#pragma mark - ReaderHandleIOS
|
|
5
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
@implementation ReaderHandleIOS {
|
|
8
|
+
NSLock *_lock;
|
|
9
|
+
int64_t _bytesReadBacking;
|
|
10
|
+
BOOL _isEOFBacking;
|
|
11
|
+
BOOL _isClosedBacking;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static NSInteger _readerNextId = 0;
|
|
15
|
+
static NSLock *_readerIdLock = nil;
|
|
16
|
+
|
|
17
|
+
+ (void)initialize {
|
|
18
|
+
if (self == [ReaderHandleIOS class]) {
|
|
19
|
+
_readerIdLock = [NSLock new];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
+ (NSInteger)nextUniqueId {
|
|
24
|
+
[_readerIdLock lock];
|
|
25
|
+
NSInteger uid = ++_readerNextId;
|
|
26
|
+
[_readerIdLock unlock];
|
|
27
|
+
return uid;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
- (nullable instancetype)initWithPath:(NSString *)path
|
|
31
|
+
bufferSize:(NSInteger)bufferSize
|
|
32
|
+
error:(NSError **)error {
|
|
33
|
+
self = [super init];
|
|
34
|
+
if (!self) return nil;
|
|
35
|
+
|
|
36
|
+
NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:path];
|
|
37
|
+
if (!stream) {
|
|
38
|
+
if (error) {
|
|
39
|
+
*error = [NSError errorWithDomain:@"BufferedBlob" code:1
|
|
40
|
+
userInfo:@{NSLocalizedDescriptionKey:
|
|
41
|
+
[NSString stringWithFormat:@"[FILE_NOT_FOUND] Could not open file: %@", path]}];
|
|
42
|
+
}
|
|
43
|
+
return nil;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_inputStream = stream;
|
|
47
|
+
_bufferSize = bufferSize;
|
|
48
|
+
_lock = [NSLock new];
|
|
49
|
+
_bytesReadBacking = 0;
|
|
50
|
+
_isEOFBacking = NO;
|
|
51
|
+
_isClosedBacking = NO;
|
|
52
|
+
|
|
53
|
+
NSString *label = [NSString stringWithFormat:@"com.bufferedblob.reader.%ld", (long)[ReaderHandleIOS nextUniqueId]];
|
|
54
|
+
_queue = dispatch_queue_create(label.UTF8String, DISPATCH_QUEUE_SERIAL);
|
|
55
|
+
dispatch_set_target_queue(_queue, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
|
|
56
|
+
|
|
57
|
+
// Get file size
|
|
58
|
+
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:error];
|
|
59
|
+
if (!attrs) return nil;
|
|
60
|
+
_fileSize = [attrs[NSFileSize] longLongValue];
|
|
61
|
+
|
|
62
|
+
[stream open];
|
|
63
|
+
if (stream.streamStatus == NSStreamStatusError) {
|
|
64
|
+
[stream close];
|
|
65
|
+
if (error) {
|
|
66
|
+
*error = [NSError errorWithDomain:@"BufferedBlob" code:1
|
|
67
|
+
userInfo:@{NSLocalizedDescriptionKey:
|
|
68
|
+
[NSString stringWithFormat:@"[FILE_NOT_FOUND] Failed to open stream: %@", path]}];
|
|
69
|
+
}
|
|
70
|
+
return nil;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return self;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (int64_t)bytesRead {
|
|
77
|
+
[_lock lock];
|
|
78
|
+
int64_t val = _bytesReadBacking;
|
|
79
|
+
[_lock unlock];
|
|
80
|
+
return val;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
- (void)setBytesRead:(int64_t)bytesRead {
|
|
84
|
+
[_lock lock];
|
|
85
|
+
_bytesReadBacking = bytesRead;
|
|
86
|
+
[_lock unlock];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (BOOL)isEOF {
|
|
90
|
+
[_lock lock];
|
|
91
|
+
BOOL val = _isEOFBacking;
|
|
92
|
+
[_lock unlock];
|
|
93
|
+
return val;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
- (void)setIsEOF:(BOOL)isEOF {
|
|
97
|
+
[_lock lock];
|
|
98
|
+
_isEOFBacking = isEOF;
|
|
99
|
+
[_lock unlock];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
- (BOOL)isClosed {
|
|
103
|
+
[_lock lock];
|
|
104
|
+
BOOL val = _isClosedBacking;
|
|
105
|
+
[_lock unlock];
|
|
106
|
+
return val;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
- (void)setIsClosed:(BOOL)isClosed {
|
|
110
|
+
[_lock lock];
|
|
111
|
+
_isClosedBacking = isClosed;
|
|
112
|
+
[_lock unlock];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
- (void)closeHandle {
|
|
116
|
+
[_lock lock];
|
|
117
|
+
if (_isClosedBacking) {
|
|
118
|
+
[_lock unlock];
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
_isClosedBacking = YES;
|
|
122
|
+
NSInputStream *stream = _inputStream;
|
|
123
|
+
[_lock unlock];
|
|
124
|
+
// Dispatch stream close to the serial queue so it runs AFTER
|
|
125
|
+
// all pending I/O blocks have drained.
|
|
126
|
+
dispatch_async(_queue, ^{
|
|
127
|
+
[stream close];
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
- (void)dealloc {
|
|
132
|
+
[self closeHandle];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@end
|
|
136
|
+
|
|
137
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
138
|
+
#pragma mark - WriterHandleIOS
|
|
139
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
@implementation WriterHandleIOS {
|
|
142
|
+
NSLock *_lock;
|
|
143
|
+
int64_t _bytesWrittenBacking;
|
|
144
|
+
BOOL _isClosedBacking;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static NSInteger _writerNextId = 0;
|
|
148
|
+
static NSLock *_writerIdLock = nil;
|
|
149
|
+
|
|
150
|
+
+ (void)initialize {
|
|
151
|
+
if (self == [WriterHandleIOS class]) {
|
|
152
|
+
_writerIdLock = [NSLock new];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
+ (NSInteger)nextUniqueId {
|
|
157
|
+
[_writerIdLock lock];
|
|
158
|
+
NSInteger uid = ++_writerNextId;
|
|
159
|
+
[_writerIdLock unlock];
|
|
160
|
+
return uid;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
- (nullable instancetype)initWithPath:(NSString *)path
|
|
164
|
+
append:(BOOL)append
|
|
165
|
+
error:(NSError **)error {
|
|
166
|
+
self = [super init];
|
|
167
|
+
if (!self) return nil;
|
|
168
|
+
|
|
169
|
+
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:path append:append];
|
|
170
|
+
if (!stream) {
|
|
171
|
+
if (error) {
|
|
172
|
+
*error = [NSError errorWithDomain:@"BufferedBlob" code:1
|
|
173
|
+
userInfo:@{NSLocalizedDescriptionKey:
|
|
174
|
+
[NSString stringWithFormat:@"[FILE_NOT_FOUND] Could not open file for writing: %@", path]}];
|
|
175
|
+
}
|
|
176
|
+
return nil;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_outputStream = stream;
|
|
180
|
+
_lock = [NSLock new];
|
|
181
|
+
_bytesWrittenBacking = 0;
|
|
182
|
+
_isClosedBacking = NO;
|
|
183
|
+
|
|
184
|
+
NSString *label = [NSString stringWithFormat:@"com.bufferedblob.writer.%ld", (long)[WriterHandleIOS nextUniqueId]];
|
|
185
|
+
_queue = dispatch_queue_create(label.UTF8String, DISPATCH_QUEUE_SERIAL);
|
|
186
|
+
dispatch_set_target_queue(_queue, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
|
|
187
|
+
|
|
188
|
+
[stream open];
|
|
189
|
+
if (stream.streamStatus == NSStreamStatusError) {
|
|
190
|
+
[stream close];
|
|
191
|
+
if (error) {
|
|
192
|
+
*error = [NSError errorWithDomain:@"BufferedBlob" code:1
|
|
193
|
+
userInfo:@{NSLocalizedDescriptionKey:
|
|
194
|
+
[NSString stringWithFormat:@"[FILE_NOT_FOUND] Failed to open write stream: %@", path]}];
|
|
195
|
+
}
|
|
196
|
+
return nil;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return self;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
- (int64_t)bytesWritten {
|
|
203
|
+
[_lock lock];
|
|
204
|
+
int64_t val = _bytesWrittenBacking;
|
|
205
|
+
[_lock unlock];
|
|
206
|
+
return val;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
- (void)setBytesWritten:(int64_t)bytesWritten {
|
|
210
|
+
[_lock lock];
|
|
211
|
+
_bytesWrittenBacking = bytesWritten;
|
|
212
|
+
[_lock unlock];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
- (BOOL)isClosed {
|
|
216
|
+
[_lock lock];
|
|
217
|
+
BOOL val = _isClosedBacking;
|
|
218
|
+
[_lock unlock];
|
|
219
|
+
return val;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
- (void)setIsClosed:(BOOL)isClosed {
|
|
223
|
+
[_lock lock];
|
|
224
|
+
_isClosedBacking = isClosed;
|
|
225
|
+
[_lock unlock];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
- (void)closeHandle {
|
|
229
|
+
[_lock lock];
|
|
230
|
+
if (_isClosedBacking) {
|
|
231
|
+
[_lock unlock];
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
_isClosedBacking = YES;
|
|
235
|
+
NSOutputStream *stream = _outputStream;
|
|
236
|
+
[_lock unlock];
|
|
237
|
+
dispatch_async(_queue, ^{
|
|
238
|
+
[stream close];
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
- (void)dealloc {
|
|
243
|
+
[self closeHandle];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@end
|
|
247
|
+
|
|
248
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
249
|
+
#pragma mark - DownloaderHandleIOS
|
|
250
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
@implementation DownloaderHandleIOS {
|
|
253
|
+
NSLock *_lock;
|
|
254
|
+
BOOL _isCancelledBacking;
|
|
255
|
+
NSURLSession *_session;
|
|
256
|
+
NSURLSessionTask *_task;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
static NSInteger _downloaderNextId = 0;
|
|
260
|
+
static NSLock *_downloaderIdLock = nil;
|
|
261
|
+
|
|
262
|
+
+ (void)initialize {
|
|
263
|
+
if (self == [DownloaderHandleIOS class]) {
|
|
264
|
+
_downloaderIdLock = [NSLock new];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
+ (NSInteger)nextUniqueId {
|
|
269
|
+
[_downloaderIdLock lock];
|
|
270
|
+
NSInteger uid = ++_downloaderNextId;
|
|
271
|
+
[_downloaderIdLock unlock];
|
|
272
|
+
return uid;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
- (instancetype)initWithURL:(NSString *)url
|
|
276
|
+
destPath:(NSString *)destPath
|
|
277
|
+
headers:(NSDictionary<NSString *, NSString *> *)headers {
|
|
278
|
+
self = [super init];
|
|
279
|
+
if (self) {
|
|
280
|
+
_url = [url copy];
|
|
281
|
+
_destPath = [destPath copy];
|
|
282
|
+
_headers = [headers copy];
|
|
283
|
+
_lock = [NSLock new];
|
|
284
|
+
_isCancelledBacking = NO;
|
|
285
|
+
|
|
286
|
+
NSString *label = [NSString stringWithFormat:@"com.bufferedblob.downloader.%ld", (long)[DownloaderHandleIOS nextUniqueId]];
|
|
287
|
+
_queue = dispatch_queue_create(label.UTF8String, DISPATCH_QUEUE_SERIAL);
|
|
288
|
+
dispatch_set_target_queue(_queue, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
|
|
289
|
+
}
|
|
290
|
+
return self;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
- (BOOL)isCancelled {
|
|
294
|
+
[_lock lock];
|
|
295
|
+
BOOL val = _isCancelledBacking;
|
|
296
|
+
[_lock unlock];
|
|
297
|
+
return val;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
- (void)setIsCancelled:(BOOL)isCancelled {
|
|
301
|
+
[_lock lock];
|
|
302
|
+
_isCancelledBacking = isCancelled;
|
|
303
|
+
[_lock unlock];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
- (void)storeSession:(NSURLSession *)session task:(NSURLSessionTask *)task {
|
|
307
|
+
[_lock lock];
|
|
308
|
+
_session = session;
|
|
309
|
+
_task = task;
|
|
310
|
+
[_lock unlock];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
- (void)cancel {
|
|
314
|
+
[_lock lock];
|
|
315
|
+
if (_isCancelledBacking) {
|
|
316
|
+
[_lock unlock];
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
_isCancelledBacking = YES;
|
|
320
|
+
NSURLSession *session = _session;
|
|
321
|
+
NSURLSessionTask *task = _task;
|
|
322
|
+
[_lock unlock];
|
|
323
|
+
|
|
324
|
+
// Cancel outside the lock to avoid potential deadlock with delegate callbacks
|
|
325
|
+
[task cancel];
|
|
326
|
+
[session invalidateAndCancel];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
- (void)closeHandle {
|
|
330
|
+
[self cancel];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<!-- Parent: ../AGENTS.md -->
|
|
2
|
+
<!-- Generated: 2026-02-15 -->
|
|
3
|
+
|
|
4
|
+
# src/
|
|
5
|
+
|
|
6
|
+
TypeScript API layer: Turbo Module spec, native module interface, streaming proxy, and high-level file operations.
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Provides the JavaScript interface to the native BufferedBlob module:
|
|
11
|
+
- **Turbo Module specification** (NativeBufferedBlob.ts) — codegen input for handle factories and FS ops
|
|
12
|
+
- **Streaming proxy** (module.ts) — JSI HostObject accessor, install() wiring
|
|
13
|
+
- **Type wrappers** (types.ts) — BlobReader/BlobWriter interfaces with property proxying
|
|
14
|
+
- **Error handling** (errors.ts) — ErrorCode enum and wrapError() utility
|
|
15
|
+
- **Paths** (paths.ts) — Dirs constants and path utilities
|
|
16
|
+
|
|
17
|
+
## Key Files
|
|
18
|
+
|
|
19
|
+
| File | Description |
|
|
20
|
+
|------|-------------|
|
|
21
|
+
| `NativeBufferedBlob.ts` | Turbo Module spec: install(), handle factories, FS ops, hashFile. Codegen input. |
|
|
22
|
+
| `module.ts` | NativeModule (TurboModuleRegistry), StreamingProxy interface, getStreamingProxy() |
|
|
23
|
+
| `types.ts` | HashAlgorithm, FileType enums; FileInfo, BlobReader, BlobWriter interfaces; wrapReader/wrapWriter |
|
|
24
|
+
| `errors.ts` | BlobError class, ErrorCode enum, wrapError() helper |
|
|
25
|
+
| `paths.ts` | Dirs constants (documentDir, cacheDir, tempDir, downloadDir); join(), dirname(), basename(), extname() |
|
|
26
|
+
| `index.ts` | Barrel exports for public API |
|
|
27
|
+
|
|
28
|
+
## Subdirectories
|
|
29
|
+
|
|
30
|
+
| Directory | Purpose |
|
|
31
|
+
|-----------|---------|
|
|
32
|
+
| `api/` | High-level file operations, download, hashing, streaming wrappers |
|
|
33
|
+
|
|
34
|
+
## For AI Agents
|
|
35
|
+
|
|
36
|
+
### Working In This Directory
|
|
37
|
+
|
|
38
|
+
1. **Turbo Module spec**: Changes to `NativeBufferedBlob.ts` trigger codegen. After editing, run `yarn prepare` to regenerate native module headers.
|
|
39
|
+
2. **Streaming proxy access**: `getStreamingProxy()` returns the JSI HostObject installed by native code. Always call `NativeModule.install()` first (done in module.ts).
|
|
40
|
+
3. **Handle pattern**: Turbo Module returns numeric handles. Pass to streaming proxy methods. Always close handles to release native resources.
|
|
41
|
+
4. **Type safety**: Use strict TypeScript. BlobReader/BlobWriter are interface wrappers; do NOT spread HostObject properties (getters would be lost).
|
|
42
|
+
5. **Error propagation**: Catch errors from native calls; use `wrapError()` to normalize error messages.
|
|
43
|
+
|
|
44
|
+
### Testing Requirements
|
|
45
|
+
|
|
46
|
+
- **Type checking**: Verify no TypeScript errors in strict mode
|
|
47
|
+
- **Module loading**: Verify `install()` succeeds and JSI HostObject is wired
|
|
48
|
+
- **Handle cleanup**: Verify handles are closed; no dangling native resources
|
|
49
|
+
- **Error cases**: Test file not found, invalid paths, invalid buffer sizes, cancelled operations
|
|
50
|
+
|
|
51
|
+
### Common Patterns
|
|
52
|
+
|
|
53
|
+
1. **Create reader**: `const handle = NativeModule.openRead(path, bufferSize)` -> `const reader = wrapReader(handle, proxy)` -> `reader.readNextChunk()` -> `reader.close()`
|
|
54
|
+
2. **Create writer**: `const handle = NativeModule.openWrite(path, append)` -> `const writer = wrapWriter(handle, proxy)` -> `writer.write(data)` -> `writer.flush()` -> `writer.close()`
|
|
55
|
+
3. **File ops**: `exists()`, `stat()`, `mkdir()`, `ls()`, `cp()`, `mv()`, `unlink()` all return Promises
|
|
56
|
+
4. **Hash file**: `hashFile(path, 'sha256' | 'md5')` streams file without loading into memory
|
|
57
|
+
5. **Download with progress**: Use `download({ url, destPath, onProgress })` API; streaming proxy handles details
|
|
58
|
+
|
|
59
|
+
## Dependencies
|
|
60
|
+
|
|
61
|
+
### Internal
|
|
62
|
+
- Turbo Module spec generated from `NativeBufferedBlob.ts` at build time
|
|
63
|
+
- `module.ts` calls `install()` on first import (side effect)
|
|
64
|
+
- `api/` layer depends on NativeModule and getStreamingProxy()
|
|
65
|
+
|
|
66
|
+
### External
|
|
67
|
+
- **React Native** >= 0.76.0 (TurboModuleRegistry, JSI)
|
|
68
|
+
- **TypeScript** ^5.9.2 (type checking, codegen)
|
|
69
|
+
|
|
70
|
+
<!-- MANUAL: Document API changes, Turbo Module version bumps, deprecations -->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeBufferedBlob.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAoDlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!-- Parent: ../AGENTS.md -->
|
|
2
|
+
<!-- Generated: 2026-02-15 -->
|
|
3
|
+
|
|
4
|
+
# src/api/
|
|
5
|
+
|
|
6
|
+
High-level convenience APIs for file operations, streaming, hashing, and downloads.
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Provide idiomatic TypeScript wrappers around Turbo Module calls and JSI HostObject streaming:
|
|
11
|
+
- **File operations**: exists, stat, mkdir, ls, cp, mv, unlink
|
|
12
|
+
- **Streaming**: readFile (deprecated), writeFile (deprecated)
|
|
13
|
+
- **Hashing**: hashFile with streaming (SHA256, MD5)
|
|
14
|
+
- **Downloads**: download with progress callback
|
|
15
|
+
|
|
16
|
+
## Key Files
|
|
17
|
+
|
|
18
|
+
| File | Description |
|
|
19
|
+
|------|-------------|
|
|
20
|
+
| `fileOps.ts` | FS operations: exists, stat, mkdir, ls, cp, mv, unlink. All return Promises. |
|
|
21
|
+
| `hash.ts` | hashFile(path, algorithm) → Promise<string>. Streams file; supports 'sha256', 'md5'. |
|
|
22
|
+
| `download.ts` | download(options) → Promise<void>. Returns DownloadOptions interface, handles progress callback. |
|
|
23
|
+
| `readFile.ts` | DEPRECATED: createReader(path, bufferSize) → BlobReader. Use openRead() + wrapReader() directly. |
|
|
24
|
+
| `writeFile.ts` | DEPRECATED: createWriter(path, append) → BlobWriter. Use openWrite() + wrapWriter() directly. |
|
|
25
|
+
|
|
26
|
+
## For AI Agents
|
|
27
|
+
|
|
28
|
+
### Working In This Directory
|
|
29
|
+
|
|
30
|
+
1. **File operations**: All async. Return Promises that resolve/reject with platform-specific error codes.
|
|
31
|
+
2. **Streaming shortcuts**: readFile/writeFile are deprecated convenience wrappers. New code should use `openRead()` + `wrapReader()` directly for explicit handle management.
|
|
32
|
+
3. **Download pattern**: `download()` creates handle, calls JSI streaming startDownload, manages progress callback, cleans up handle in finally block.
|
|
33
|
+
4. **Error handling**: Use `wrapError()` from parent module to normalize native errors.
|
|
34
|
+
5. **Handle lifecycle**: Always close streaming handles (readFile/writeFile do this implicitly; direct handle usage requires explicit close).
|
|
35
|
+
|
|
36
|
+
### Testing Requirements
|
|
37
|
+
|
|
38
|
+
- **File ops**: Create temp files, test exists/stat/mkdir/ls/cp/mv/unlink
|
|
39
|
+
- **Hashing**: Verify hash output against known digests (sha256, md5)
|
|
40
|
+
- **Download**: Test with HTTP server, verify progress callback fires, verify file written
|
|
41
|
+
- **Error cases**: Test file not found, permission denied, invalid paths, cancelled downloads
|
|
42
|
+
|
|
43
|
+
### Common Patterns
|
|
44
|
+
|
|
45
|
+
1. **Check file exists**: `const exists = await exists(path)`
|
|
46
|
+
2. **Get file info**: `const info = await stat(path)` → {path, name, size, type, lastModified}
|
|
47
|
+
3. **List directory**: `const files = await ls(dirPath)` → FileInfo[]
|
|
48
|
+
4. **Copy file**: `await cp(srcPath, destPath)`
|
|
49
|
+
5. **Hash file**: `const hash = await hashFile(path, 'sha256')`
|
|
50
|
+
6. **Download with progress**: `await download({ url, destPath, headers: {}, onProgress: (p) => console.log(p.progress) })`
|
|
51
|
+
|
|
52
|
+
## Dependencies
|
|
53
|
+
|
|
54
|
+
### Internal
|
|
55
|
+
- `../module.ts` — NativeModule, getStreamingProxy()
|
|
56
|
+
- `../types.ts` — BlobReader, BlobWriter, FileInfo, DownloadProgress, HashAlgorithm
|
|
57
|
+
- `../errors.ts` — wrapError()
|
|
58
|
+
|
|
59
|
+
### External
|
|
60
|
+
- **React Native** >= 0.76.0 (TurboModuleRegistry for NativeModule calls)
|
|
61
|
+
|
|
62
|
+
<!-- MANUAL: Document deprecated APIs, migration guides for readFile/writeFile users -->
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeModule, getStreamingProxy } from "../module.js";
|
|
4
|
+
import { wrapError } from "../errors.js";
|
|
5
|
+
export function download(options) {
|
|
6
|
+
const {
|
|
7
|
+
url,
|
|
8
|
+
destPath,
|
|
9
|
+
headers = {},
|
|
10
|
+
onProgress
|
|
11
|
+
} = options;
|
|
12
|
+
try {
|
|
13
|
+
const handleId = NativeModule.createDownload(url, destPath, headers);
|
|
14
|
+
const streaming = getStreamingProxy();
|
|
15
|
+
const progressCallback = onProgress ? (bytesDownloaded, totalBytes, progress) => {
|
|
16
|
+
onProgress({
|
|
17
|
+
bytesDownloaded,
|
|
18
|
+
totalBytes,
|
|
19
|
+
progress
|
|
20
|
+
});
|
|
21
|
+
} : (_b, _t, _p) => {};
|
|
22
|
+
const promise = (async () => {
|
|
23
|
+
try {
|
|
24
|
+
await streaming.startDownload(handleId, progressCallback);
|
|
25
|
+
} finally {
|
|
26
|
+
NativeModule.closeHandle(handleId);
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
29
|
+
const cancel = () => {
|
|
30
|
+
streaming.cancelDownload(handleId);
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
promise,
|
|
34
|
+
cancel
|
|
35
|
+
};
|
|
36
|
+
} catch (e) {
|
|
37
|
+
throw wrapError(e, destPath);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModule","getStreamingProxy","wrapError","download","options","url","destPath","headers","onProgress","handleId","createDownload","streaming","progressCallback","bytesDownloaded","totalBytes","progress","_b","_t","_p","promise","startDownload","closeHandle","cancel","cancelDownload","e"],"sourceRoot":"../../../src","sources":["api/download.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,iBAAiB,QAAQ,cAAW;AAC3D,SAASC,SAAS,QAAQ,cAAW;AAerC,OAAO,SAASC,QAAQA,CAACC,OAAwB,EAAkB;EACjE,MAAM;IAAEC,GAAG;IAAEC,QAAQ;IAAEC,OAAO,GAAG,CAAC,CAAC;IAAEC;EAAW,CAAC,GAAGJ,OAAO;EAE3D,IAAI;IACF,MAAMK,QAAQ,GAAGT,YAAY,CAACU,cAAc,CAACL,GAAG,EAAEC,QAAQ,EAAEC,OAAO,CAAC;IACpE,MAAMI,SAAS,GAAGV,iBAAiB,CAAC,CAAC;IAErC,MAAMW,gBAAgB,GAAGJ,UAAU,GAC/B,CAACK,eAAuB,EAAEC,UAAkB,EAAEC,QAAgB,KAAK;MACjEP,UAAU,CAAC;QAAEK,eAAe;QAAEC,UAAU;QAAEC;MAAS,CAAC,CAAC;IACvD,CAAC,GACD,CAACC,EAAU,EAAEC,EAAU,EAAEC,EAAU,KAAK,CAAC,CAAC;IAE9C,MAAMC,OAAO,GAAG,CAAC,YAAY;MAC3B,IAAI;QACF,MAAMR,SAAS,CAACS,aAAa,CAACX,QAAQ,EAAEG,gBAAgB,CAAC;MAC3D,CAAC,SAAS;QACRZ,YAAY,CAACqB,WAAW,CAACZ,QAAQ,CAAC;MACpC;IACF,CAAC,EAAE,CAAC;IAEJ,MAAMa,MAAM,GAAGA,CAAA,KAAM;MACnBX,SAAS,CAACY,cAAc,CAACd,QAAQ,CAAC;IACpC,CAAC;IAED,OAAO;MAAEU,OAAO;MAAEG;IAAO,CAAC;EAC5B,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV,MAAMtB,SAAS,CAACsB,CAAC,EAAElB,QAAQ,CAAC;EAC9B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeModule } from "../module.js";
|
|
4
|
+
import { wrapError } from "../errors.js";
|
|
5
|
+
import { FileType } from "../types.js";
|
|
6
|
+
function toFileType(raw) {
|
|
7
|
+
const values = Object.values(FileType);
|
|
8
|
+
return values.includes(raw) ? raw : FileType.UNKNOWN;
|
|
9
|
+
}
|
|
10
|
+
function mapFileInfo(raw) {
|
|
11
|
+
return {
|
|
12
|
+
path: raw.path,
|
|
13
|
+
name: raw.name,
|
|
14
|
+
size: raw.size,
|
|
15
|
+
type: toFileType(raw.type),
|
|
16
|
+
lastModified: raw.lastModified
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export async function exists(path) {
|
|
20
|
+
try {
|
|
21
|
+
return await NativeModule.exists(path);
|
|
22
|
+
} catch (e) {
|
|
23
|
+
throw wrapError(e, path);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function stat(path) {
|
|
27
|
+
try {
|
|
28
|
+
const raw = await NativeModule.stat(path);
|
|
29
|
+
return mapFileInfo(raw);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
throw wrapError(e, path);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function unlink(path) {
|
|
35
|
+
try {
|
|
36
|
+
await NativeModule.unlink(path);
|
|
37
|
+
} catch (e) {
|
|
38
|
+
throw wrapError(e, path);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function mkdir(path) {
|
|
42
|
+
try {
|
|
43
|
+
await NativeModule.mkdir(path);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
throw wrapError(e, path);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function ls(path) {
|
|
49
|
+
try {
|
|
50
|
+
const rawList = await NativeModule.ls(path);
|
|
51
|
+
return rawList.map(mapFileInfo);
|
|
52
|
+
} catch (e) {
|
|
53
|
+
throw wrapError(e, path);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function cp(srcPath, destPath) {
|
|
57
|
+
try {
|
|
58
|
+
await NativeModule.cp(srcPath, destPath);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
throw wrapError(e, srcPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function mv(srcPath, destPath) {
|
|
64
|
+
try {
|
|
65
|
+
await NativeModule.mv(srcPath, destPath);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
throw wrapError(e, srcPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=fileOps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModule","wrapError","FileType","toFileType","raw","values","Object","includes","UNKNOWN","mapFileInfo","path","name","size","type","lastModified","exists","e","stat","unlink","mkdir","ls","rawList","map","cp","srcPath","destPath","mv"],"sourceRoot":"../../../src","sources":["api/fileOps.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,cAAW;AACxC,SAASC,SAAS,QAAQ,cAAW;AAErC,SAASC,QAAQ,QAAQ,aAAU;AAEnC,SAASC,UAAUA,CAACC,GAAW,EAAY;EACzC,MAAMC,MAAgB,GAAGC,MAAM,CAACD,MAAM,CAACH,QAAQ,CAAC;EAChD,OAAOG,MAAM,CAACE,QAAQ,CAACH,GAAG,CAAC,GAAIA,GAAG,GAAgBF,QAAQ,CAACM,OAAO;AACpE;AAEA,SAASC,WAAWA,CAACL,GAMpB,EAAY;EACX,OAAO;IACLM,IAAI,EAAEN,GAAG,CAACM,IAAI;IACdC,IAAI,EAAEP,GAAG,CAACO,IAAI;IACdC,IAAI,EAAER,GAAG,CAACQ,IAAI;IACdC,IAAI,EAAEV,UAAU,CAACC,GAAG,CAACS,IAAI,CAAC;IAC1BC,YAAY,EAAEV,GAAG,CAACU;EACpB,CAAC;AACH;AAEA,OAAO,eAAeC,MAAMA,CAACL,IAAY,EAAoB;EAC3D,IAAI;IACF,OAAO,MAAMV,YAAY,CAACe,MAAM,CAACL,IAAI,CAAC;EACxC,CAAC,CAAC,OAAOM,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF;AAEA,OAAO,eAAeO,IAAIA,CAACP,IAAY,EAAqB;EAC1D,IAAI;IACF,MAAMN,GAAG,GAAG,MAAMJ,YAAY,CAACiB,IAAI,CAACP,IAAI,CAAC;IACzC,OAAOD,WAAW,CAACL,GAAG,CAAC;EACzB,CAAC,CAAC,OAAOY,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF;AAEA,OAAO,eAAeQ,MAAMA,CAACR,IAAY,EAAiB;EACxD,IAAI;IACF,MAAMV,YAAY,CAACkB,MAAM,CAACR,IAAI,CAAC;EACjC,CAAC,CAAC,OAAOM,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF;AAEA,OAAO,eAAeS,KAAKA,CAACT,IAAY,EAAiB;EACvD,IAAI;IACF,MAAMV,YAAY,CAACmB,KAAK,CAACT,IAAI,CAAC;EAChC,CAAC,CAAC,OAAOM,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF;AAEA,OAAO,eAAeU,EAAEA,CAACV,IAAY,EAAuB;EAC1D,IAAI;IACF,MAAMW,OAAO,GAAG,MAAMrB,YAAY,CAACoB,EAAE,CAACV,IAAI,CAAC;IAC3C,OAAOW,OAAO,CAACC,GAAG,CAACb,WAAW,CAAC;EACjC,CAAC,CAAC,OAAOO,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF;AAEA,OAAO,eAAea,EAAEA,CAACC,OAAe,EAAEC,QAAgB,EAAiB;EACzE,IAAI;IACF,MAAMzB,YAAY,CAACuB,EAAE,CAACC,OAAO,EAAEC,QAAQ,CAAC;EAC1C,CAAC,CAAC,OAAOT,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEQ,OAAO,CAAC;EAC7B;AACF;AAEA,OAAO,eAAeE,EAAEA,CAACF,OAAe,EAAEC,QAAgB,EAAiB;EACzE,IAAI;IACF,MAAMzB,YAAY,CAAC0B,EAAE,CAACF,OAAO,EAAEC,QAAQ,CAAC;EAC1C,CAAC,CAAC,OAAOT,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAEQ,OAAO,CAAC;EAC7B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeModule } from "../module.js";
|
|
4
|
+
import { wrapError } from "../errors.js";
|
|
5
|
+
import { HashAlgorithm } from "../types.js";
|
|
6
|
+
export async function hashFile(path, algorithm = HashAlgorithm.SHA256) {
|
|
7
|
+
try {
|
|
8
|
+
return await NativeModule.hashFile(path, algorithm);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
throw wrapError(e, path);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModule","wrapError","HashAlgorithm","hashFile","path","algorithm","SHA256","e"],"sourceRoot":"../../../src","sources":["api/hash.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,cAAW;AACxC,SAASC,SAAS,QAAQ,cAAW;AACrC,SAASC,aAAa,QAAQ,aAAU;AAExC,OAAO,eAAeC,QAAQA,CAC5BC,IAAY,EACZC,SAAwB,GAAGH,aAAa,CAACI,MAAM,EAC9B;EACjB,IAAI;IACF,OAAO,MAAMN,YAAY,CAACG,QAAQ,CAACC,IAAI,EAAEC,SAAS,CAAC;EACrD,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV,MAAMN,SAAS,CAACM,CAAC,EAAEH,IAAI,CAAC;EAC1B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeModule, getStreamingProxy } from "../module.js";
|
|
4
|
+
import { wrapError, BlobError, ErrorCode } from "../errors.js";
|
|
5
|
+
import { wrapReader } from "../wrappers.js";
|
|
6
|
+
const DEFAULT_BUFFER_SIZE = 65536; // 64KB
|
|
7
|
+
|
|
8
|
+
export function createReader(path, bufferSize = DEFAULT_BUFFER_SIZE) {
|
|
9
|
+
try {
|
|
10
|
+
if (!Number.isFinite(bufferSize) || bufferSize < 4096 || bufferSize > 4194304) {
|
|
11
|
+
throw new BlobError(ErrorCode.INVALID_ARGUMENT, `bufferSize must be between 4096 and 4194304, got ${bufferSize}`, path);
|
|
12
|
+
}
|
|
13
|
+
const handleId = NativeModule.openRead(path, bufferSize);
|
|
14
|
+
if (handleId < 0) {
|
|
15
|
+
throw new BlobError(ErrorCode.IO_ERROR, 'Failed to open file for reading', path);
|
|
16
|
+
}
|
|
17
|
+
const streaming = getStreamingProxy();
|
|
18
|
+
return wrapReader(handleId, streaming);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw wrapError(e, path);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=readFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModule","getStreamingProxy","wrapError","BlobError","ErrorCode","wrapReader","DEFAULT_BUFFER_SIZE","createReader","path","bufferSize","Number","isFinite","INVALID_ARGUMENT","handleId","openRead","IO_ERROR","streaming","e"],"sourceRoot":"../../../src","sources":["api/readFile.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,iBAAiB,QAAQ,cAAW;AAC3D,SAASC,SAAS,EAAEC,SAAS,EAAEC,SAAS,QAAQ,cAAW;AAC3D,SAASC,UAAU,QAAQ,gBAAa;AAGxC,MAAMC,mBAAmB,GAAG,KAAK,CAAC,CAAC;;AAEnC,OAAO,SAASC,YAAYA,CAC1BC,IAAY,EACZC,UAAkB,GAAGH,mBAAmB,EAC5B;EACZ,IAAI;IACF,IACE,CAACI,MAAM,CAACC,QAAQ,CAACF,UAAU,CAAC,IAC5BA,UAAU,GAAG,IAAI,IACjBA,UAAU,GAAG,OAAO,EACpB;MACA,MAAM,IAAIN,SAAS,CACjBC,SAAS,CAACQ,gBAAgB,EAC1B,oDAAoDH,UAAU,EAAE,EAChED,IACF,CAAC;IACH;IACA,MAAMK,QAAQ,GAAGb,YAAY,CAACc,QAAQ,CAACN,IAAI,EAAEC,UAAU,CAAC;IACxD,IAAII,QAAQ,GAAG,CAAC,EAAE;MAChB,MAAM,IAAIV,SAAS,CACjBC,SAAS,CAACW,QAAQ,EAClB,iCAAiC,EACjCP,IACF,CAAC;IACH;IACA,MAAMQ,SAAS,GAAGf,iBAAiB,CAAC,CAAC;IACrC,OAAOI,UAAU,CAACQ,QAAQ,EAAEG,SAAS,CAAC;EACxC,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,MAAMf,SAAS,CAACe,CAAC,EAAET,IAAI,CAAC;EAC1B;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeModule, getStreamingProxy } from "../module.js";
|
|
4
|
+
import { wrapError, BlobError, ErrorCode } from "../errors.js";
|
|
5
|
+
import { wrapWriter } from "../wrappers.js";
|
|
6
|
+
export function createWriter(path, append = false) {
|
|
7
|
+
try {
|
|
8
|
+
const handleId = NativeModule.openWrite(path, append);
|
|
9
|
+
if (handleId < 0) {
|
|
10
|
+
throw new BlobError(ErrorCode.IO_ERROR, 'Failed to open file for writing', path);
|
|
11
|
+
}
|
|
12
|
+
const streaming = getStreamingProxy();
|
|
13
|
+
return wrapWriter(handleId, streaming);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
throw wrapError(e, path);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=writeFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModule","getStreamingProxy","wrapError","BlobError","ErrorCode","wrapWriter","createWriter","path","append","handleId","openWrite","IO_ERROR","streaming","e"],"sourceRoot":"../../../src","sources":["api/writeFile.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,iBAAiB,QAAQ,cAAW;AAC3D,SAASC,SAAS,EAAEC,SAAS,EAAEC,SAAS,QAAQ,cAAW;AAC3D,SAASC,UAAU,QAAQ,gBAAa;AAGxC,OAAO,SAASC,YAAYA,CAC1BC,IAAY,EACZC,MAAe,GAAG,KAAK,EACX;EACZ,IAAI;IACF,MAAMC,QAAQ,GAAGT,YAAY,CAACU,SAAS,CAACH,IAAI,EAAEC,MAAM,CAAC;IACrD,IAAIC,QAAQ,GAAG,CAAC,EAAE;MAChB,MAAM,IAAIN,SAAS,CACjBC,SAAS,CAACO,QAAQ,EAClB,iCAAiC,EACjCJ,IACF,CAAC;IACH;IACA,MAAMK,SAAS,GAAGX,iBAAiB,CAAC,CAAC;IACrC,OAAOI,UAAU,CAACI,QAAQ,EAAEG,SAAS,CAAC;EACxC,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,MAAMX,SAAS,CAACW,CAAC,EAAEN,IAAI,CAAC;EAC1B;AACF","ignoreList":[]}
|