@effindomv2/fui-as 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE.md +7 -0
  2. package/browser/src/common-harness/host-imports.ts +430 -0
  3. package/browser/src/common-harness/interop.ts +39 -0
  4. package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
  5. package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
  6. package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
  7. package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
  8. package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
  9. package/browser/src/common-harness/managed-harness-session.ts +15 -0
  10. package/browser/src/common-harness/managed-harness.ts +1323 -0
  11. package/browser/src/common-harness/managed-history.ts +168 -0
  12. package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
  13. package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
  14. package/browser/src/common-harness/text-session-bridge.ts +452 -0
  15. package/browser/src/common-harness/types.ts +205 -0
  16. package/browser/src/common-harness/ui-chrome.ts +191 -0
  17. package/browser/src/common-harness/ui-imports.ts +529 -0
  18. package/browser/src/common-harness/wasm-module-cache.ts +47 -0
  19. package/browser/src/common-harness.ts +27 -0
  20. package/browser/src/file-processing-worker.ts +89 -0
  21. package/browser/src/host-events.ts +97 -0
  22. package/browser/src/host-services.ts +203 -0
  23. package/browser/src/index.ts +62 -0
  24. package/browser/src/persisted-ui-state.ts +206 -0
  25. package/browser/src/routed-harness.ts +198 -0
  26. package/browser/src/worker-bootstrap.ts +483 -0
  27. package/browser/src/worker-manager.ts +230 -0
  28. package/browser/src/worker-types.ts +50 -0
  29. package/package.json +89 -0
  30. package/scripts/build-demo-as.sh +91 -0
  31. package/scripts/build.sh +325 -0
  32. package/scripts/generate-host-events.ts +175 -0
  33. package/scripts/generate-host-services.ts +157 -0
  34. package/src/Fui.ts +205 -0
  35. package/src/FuiExports.ts +55 -0
  36. package/src/FuiPrimitives.ts +15 -0
  37. package/src/FuiWorker.ts +3 -0
  38. package/src/FuiWorkerExports.ts +6 -0
  39. package/src/bindings/ui.ts +531 -0
  40. package/src/color.ts +86 -0
  41. package/src/controls/AntiSelectionArea.ts +23 -0
  42. package/src/controls/Button.ts +750 -0
  43. package/src/controls/Checkbox.ts +181 -0
  44. package/src/controls/ContextMenu.ts +885 -0
  45. package/src/controls/ControlTemplateSet.ts +37 -0
  46. package/src/controls/Dialog.ts +355 -0
  47. package/src/controls/Dropdown.ts +856 -0
  48. package/src/controls/Form.ts +110 -0
  49. package/src/controls/NavLink.ts +211 -0
  50. package/src/controls/Popup.ts +129 -0
  51. package/src/controls/ProgressBar.ts +180 -0
  52. package/src/controls/RadioButton.ts +135 -0
  53. package/src/controls/RadioGroup.ts +244 -0
  54. package/src/controls/SelectionArea.ts +75 -0
  55. package/src/controls/Slider.ts +471 -0
  56. package/src/controls/Switch.ts +132 -0
  57. package/src/controls/TextArea.ts +20 -0
  58. package/src/controls/TextInput.ts +7 -0
  59. package/src/controls/index.ts +18 -0
  60. package/src/controls/internal/ButtonPresenter.ts +95 -0
  61. package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
  62. package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
  63. package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
  64. package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
  65. package/src/controls/internal/PopupPresenter.ts +198 -0
  66. package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
  67. package/src/controls/internal/PressableLabeledControl.ts +221 -0
  68. package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
  69. package/src/controls/internal/SliderPresenter.ts +157 -0
  70. package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
  71. package/src/controls/internal/TextInputCore.ts +695 -0
  72. package/src/controls/internal/TextInputPresenter.ts +72 -0
  73. package/src/controls/templating.ts +54 -0
  74. package/src/core/Action.ts +94 -0
  75. package/src/core/Actions.ts +37 -0
  76. package/src/core/Animation.ts +412 -0
  77. package/src/core/Application.ts +328 -0
  78. package/src/core/Assets.ts +264 -0
  79. package/src/core/AttachedProperties.ts +32 -0
  80. package/src/core/Bitmap.ts +70 -0
  81. package/src/core/BoundCallback.ts +104 -0
  82. package/src/core/Callbacks.ts +17 -0
  83. package/src/core/ContextMenuManager.ts +466 -0
  84. package/src/core/DebugApi.ts +30 -0
  85. package/src/core/Disposable.ts +10 -0
  86. package/src/core/DragDropManager.ts +179 -0
  87. package/src/core/DragGesture.ts +184 -0
  88. package/src/core/DynamicAssetIds.ts +24 -0
  89. package/src/core/Errors.ts +48 -0
  90. package/src/core/EventRouter.ts +408 -0
  91. package/src/core/ExternalDropManager.ts +122 -0
  92. package/src/core/Fetch.ts +264 -0
  93. package/src/core/FetchFfi.ts +15 -0
  94. package/src/core/File.ts +1002 -0
  95. package/src/core/FocusAdornerManager.ts +263 -0
  96. package/src/core/FocusVisibility.ts +36 -0
  97. package/src/core/FrameScheduler.ts +28 -0
  98. package/src/core/KeyboardScroll.ts +161 -0
  99. package/src/core/KeyboardScrollTracker.ts +386 -0
  100. package/src/core/Logger.ts +80 -0
  101. package/src/core/Navigation.ts +13 -0
  102. package/src/core/Node.ts +1708 -0
  103. package/src/core/PersistedState.ts +102 -0
  104. package/src/core/PersistedUiState.ts +142 -0
  105. package/src/core/Platform.ts +219 -0
  106. package/src/core/Signal.ts +89 -0
  107. package/src/core/Theme.ts +365 -0
  108. package/src/core/Timers.ts +129 -0
  109. package/src/core/ToolTip.ts +122 -0
  110. package/src/core/ToolTipManager.ts +459 -0
  111. package/src/core/Transitions.ts +34 -0
  112. package/src/core/Typography.ts +204 -0
  113. package/src/core/Worker.ts +196 -0
  114. package/src/core/bind.ts +37 -0
  115. package/src/core/event_exports.ts +596 -0
  116. package/src/core/ffi.ts +728 -0
  117. package/src/host-services/runtime.ts +25 -0
  118. package/src/nodes/FlexBox.ts +789 -0
  119. package/src/nodes/GradientStop.ts +9 -0
  120. package/src/nodes/Grid.ts +183 -0
  121. package/src/nodes/Image.ts +189 -0
  122. package/src/nodes/Portal.ts +14 -0
  123. package/src/nodes/RichText.ts +312 -0
  124. package/src/nodes/ScrollBar.ts +570 -0
  125. package/src/nodes/ScrollBox.ts +415 -0
  126. package/src/nodes/ScrollState.ts +10 -0
  127. package/src/nodes/ScrollView.ts +511 -0
  128. package/src/nodes/Svg.ts +142 -0
  129. package/src/nodes/Text.ts +145 -0
  130. package/src/nodes/TextCore.ts +558 -0
  131. package/src/nodes/VirtualList.ts +431 -0
  132. package/src/nodes/helpers.ts +25 -0
  133. package/src/nodes/index.ts +14 -0
  134. package/src/tsconfig.json +7 -0
  135. package/src/worker/Worker.ts +169 -0
  136. package/src/worker/WorkerJob.ts +65 -0
  137. package/src/worker/ffi.ts +23 -0
@@ -0,0 +1,1002 @@
1
+ import { Callback1, Handler1 } from "./Callbacks";
2
+ import { Disposable } from "./Disposable";
3
+ import { throwNullArgument } from "./Errors";
4
+ import {
5
+ fui_file_capabilities,
6
+ fui_file_create_writer,
7
+ fui_file_pick,
8
+ fui_file_process_worker_cancel,
9
+ fui_file_process_worker_start,
10
+ fui_file_read_chunk,
11
+ fui_file_save_bytes,
12
+ fui_file_save_text,
13
+ fui_file_writer_finish,
14
+ fui_file_writer_write_bytes,
15
+ fui_file_writer_write_text,
16
+ } from "./ffi";
17
+ import { warn } from "./Logger";
18
+ import { bind1 } from "./bind";
19
+
20
+ const FUNCTION_PICK_WITH = "FileOpenRequest.pickWith";
21
+ const FUNCTION_READ_BYTES_CHUNK_WITH = "BrowserFile.readBytesChunkWith";
22
+ const FUNCTION_SAVE_TEXT_WITH = "FileSaveRequest.saveTextWith";
23
+ const FUNCTION_SAVE_BYTES_WITH = "FileSaveRequest.saveBytesWith";
24
+ const FUNCTION_CREATE_WRITER_WITH = "FileSaveRequest.createWriterWith";
25
+ const FUNCTION_FILE_WORKER_PROCESS_START = "FileWorkerProcessRequest.start";
26
+ const FUNCTION_WRITE_TEXT_CHUNK_WITH = "BrowserFileWriter.writeTextChunkWith";
27
+ const FUNCTION_WRITE_BYTES_CHUNK_WITH = "BrowserFileWriter.writeBytesChunkWith";
28
+ const FUNCTION_FINISH_WITH = "BrowserFileWriter.finishWith";
29
+
30
+ const FILE_STATUS_SUCCESS: u32 = 1;
31
+ const FILE_STATUS_CANCELLED: u32 = 2;
32
+ const FILE_STATUS_ERROR: u32 = 3;
33
+
34
+ const FILE_CAPABILITY_OPEN: u32 = 1 << 0;
35
+ const FILE_CAPABILITY_READ: u32 = 1 << 1;
36
+ const FILE_CAPABILITY_SAVE: u32 = 1 << 2;
37
+ const FILE_CAPABILITY_CHUNKED_READ: u32 = 1 << 3;
38
+ const FILE_CAPABILITY_CHUNKED_WRITE: u32 = 1 << 4;
39
+ const FILE_CAPABILITY_NATIVE_SAVE_PICKER: u32 = 1 << 5;
40
+ const FILE_CAPABILITY_PROCESS_WORKER_SAVE: u32 = 1 << 6;
41
+ const REQUEST_KIND_OPEN: u32 = 1;
42
+ const REQUEST_KIND_READ: u32 = 2;
43
+ const REQUEST_KIND_SAVE: u32 = 3;
44
+ const REQUEST_KIND_CREATE_WRITER: u32 = 4;
45
+ const REQUEST_KIND_WRITE: u32 = 5;
46
+ const REQUEST_KIND_FINISH: u32 = 6;
47
+
48
+ let nextFileRequestId: u32 = 1;
49
+ const browserFiles = new Map<string, BrowserFile>();
50
+ const pendingOpenRequests = new Map<u32, PendingOpenRequest>();
51
+ const pendingReadRequests = new Map<u32, PendingReadRequest>();
52
+ const pendingSaveRequests = new Map<u32, PendingSaveRequest>();
53
+ const pendingWriterCreateRequests = new Map<u32, PendingWriterCreateRequest>();
54
+ const pendingWriterWriteRequests = new Map<u32, PendingWriterWriteRequest>();
55
+ const pendingWriterFinishRequests = new Map<u32, PendingWriterFinishRequest>();
56
+ const pendingWorkerProcessRequests = new Map<u32, FileWorkerProcessRequest>();
57
+
58
+ function encodeUtf8(text: string): Uint8Array {
59
+ return Uint8Array.wrap(String.UTF8.encode(text, false));
60
+ }
61
+
62
+ function nextRequestId(): u32 {
63
+ return nextFileRequestId++;
64
+ }
65
+
66
+ function describeFileFailure(status: u32, fallback: string): string {
67
+ if (status == FILE_STATUS_CANCELLED) {
68
+ return "File operation was cancelled.";
69
+ }
70
+ return fallback;
71
+ }
72
+
73
+ function dispatchFileError(binding: Callback1<string> | null, message: string): void {
74
+ if (binding !== null) {
75
+ binding.invoke(message);
76
+ return;
77
+ }
78
+ warn("File", message);
79
+ }
80
+
81
+ function registerPendingOpenRequest(request: PendingOpenRequest): u32 {
82
+ const requestId = nextRequestId();
83
+ pendingOpenRequests.set(requestId, request);
84
+ return requestId;
85
+ }
86
+
87
+ function registerPendingReadRequest(request: PendingReadRequest): u32 {
88
+ const requestId = nextRequestId();
89
+ pendingReadRequests.set(requestId, request);
90
+ return requestId;
91
+ }
92
+
93
+ function registerPendingSaveRequest(request: PendingSaveRequest): u32 {
94
+ const requestId = nextRequestId();
95
+ pendingSaveRequests.set(requestId, request);
96
+ return requestId;
97
+ }
98
+
99
+ function registerPendingWriterCreateRequest(request: PendingWriterCreateRequest): u32 {
100
+ const requestId = nextRequestId();
101
+ pendingWriterCreateRequests.set(requestId, request);
102
+ return requestId;
103
+ }
104
+
105
+ function registerPendingWriterWriteRequest(request: PendingWriterWriteRequest): u32 {
106
+ const requestId = nextRequestId();
107
+ pendingWriterWriteRequests.set(requestId, request);
108
+ return requestId;
109
+ }
110
+
111
+ function registerPendingWriterFinishRequest(request: PendingWriterFinishRequest): u32 {
112
+ const requestId = nextRequestId();
113
+ pendingWriterFinishRequests.set(requestId, request);
114
+ return requestId;
115
+ }
116
+
117
+ function registerPendingWorkerProcessRequest(request: FileWorkerProcessRequest): u32 {
118
+ const requestId = nextRequestId();
119
+ pendingWorkerProcessRequests.set(requestId, request);
120
+ return requestId;
121
+ }
122
+
123
+ class FileRequestDisposable implements Disposable {
124
+ private requestId: u32;
125
+ private readonly kind: u32;
126
+
127
+ constructor(kind: u32, requestId: u32) {
128
+ this.kind = kind;
129
+ this.requestId = requestId;
130
+ }
131
+
132
+ dispose(): void {
133
+ if (this.requestId == 0) {
134
+ return;
135
+ }
136
+ const requestId = this.requestId;
137
+ this.requestId = 0;
138
+ if (this.kind == REQUEST_KIND_OPEN) {
139
+ pendingOpenRequests.delete(requestId);
140
+ return;
141
+ }
142
+ if (this.kind == REQUEST_KIND_READ) {
143
+ pendingReadRequests.delete(requestId);
144
+ return;
145
+ }
146
+ if (this.kind == REQUEST_KIND_SAVE) {
147
+ pendingSaveRequests.delete(requestId);
148
+ return;
149
+ }
150
+ if (this.kind == REQUEST_KIND_CREATE_WRITER) {
151
+ pendingWriterCreateRequests.delete(requestId);
152
+ return;
153
+ }
154
+ if (this.kind == REQUEST_KIND_WRITE) {
155
+ pendingWriterWriteRequests.delete(requestId);
156
+ return;
157
+ }
158
+ if (this.kind == REQUEST_KIND_FINISH) {
159
+ pendingWriterFinishRequests.delete(requestId);
160
+ }
161
+ }
162
+ }
163
+
164
+ class PendingOpenRequest {
165
+ constructor(
166
+ readonly completeBinding: Callback1<Array<BrowserFile>>,
167
+ readonly errorBinding: Callback1<string> | null,
168
+ ) {}
169
+ }
170
+
171
+ class PendingReadRequest {
172
+ constructor(
173
+ readonly completeBinding: Callback1<FileReadChunk>,
174
+ readonly errorBinding: Callback1<string> | null,
175
+ ) {}
176
+ }
177
+
178
+ class PendingSaveRequest {
179
+ constructor(
180
+ readonly completeBinding: Callback1<FileSaveResult>,
181
+ readonly errorBinding: Callback1<string> | null,
182
+ ) {}
183
+ }
184
+
185
+ class PendingWriterCreateRequest {
186
+ constructor(
187
+ readonly completeBinding: Callback1<BrowserFileWriter>,
188
+ readonly errorBinding: Callback1<string> | null,
189
+ ) {}
190
+ }
191
+
192
+ class PendingWriterWriteRequest {
193
+ constructor(
194
+ readonly completeBinding: Callback1<FileWriteProgress>,
195
+ readonly errorBinding: Callback1<string> | null,
196
+ ) {}
197
+ }
198
+
199
+ class PendingWriterFinishRequest {
200
+ constructor(
201
+ readonly completeBinding: Callback1<FileSaveResult>,
202
+ readonly errorBinding: Callback1<string> | null,
203
+ ) {}
204
+ }
205
+
206
+ export enum FileSaveMode {
207
+ Download = 1,
208
+ NativePicker = 2,
209
+ }
210
+
211
+ export class FileCapabilities {
212
+ readonly canPickOpen: bool;
213
+ readonly canRead: bool;
214
+ readonly canSave: bool;
215
+ readonly canReadChunks: bool;
216
+ readonly canWriteChunks: bool;
217
+ readonly canUseNativeSavePicker: bool;
218
+ readonly canProcessInWorkerToPickedFile: bool;
219
+
220
+ constructor(bits: u32) {
221
+ this.canPickOpen = (bits & FILE_CAPABILITY_OPEN) != 0;
222
+ this.canRead = (bits & FILE_CAPABILITY_READ) != 0;
223
+ this.canSave = (bits & FILE_CAPABILITY_SAVE) != 0;
224
+ this.canReadChunks = (bits & FILE_CAPABILITY_CHUNKED_READ) != 0;
225
+ this.canWriteChunks = (bits & FILE_CAPABILITY_CHUNKED_WRITE) != 0;
226
+ this.canUseNativeSavePicker = (bits & FILE_CAPABILITY_NATIVE_SAVE_PICKER) != 0;
227
+ this.canProcessInWorkerToPickedFile = (bits & FILE_CAPABILITY_PROCESS_WORKER_SAVE) != 0;
228
+ }
229
+ }
230
+
231
+ export class FileReadChunk {
232
+ readonly offsetBytes: u64;
233
+ readonly fileSizeBytes: u64;
234
+ readonly bytes: Uint8Array;
235
+
236
+ constructor(offsetBytes: u64, fileSizeBytes: u64, bytes: Uint8Array) {
237
+ this.offsetBytes = offsetBytes;
238
+ this.fileSizeBytes = fileSizeBytes;
239
+ this.bytes = bytes;
240
+ }
241
+
242
+ get nextOffsetBytes(): u64 {
243
+ return this.offsetBytes + <u64>this.bytes.length;
244
+ }
245
+
246
+ get reachedEof(): bool {
247
+ return this.nextOffsetBytes >= this.fileSizeBytes;
248
+ }
249
+ }
250
+
251
+ export class FileWriteProgress {
252
+ readonly writtenBytes: u64;
253
+ readonly totalWrittenBytes: u64;
254
+
255
+ constructor(writtenBytes: u64, totalWrittenBytes: u64) {
256
+ this.writtenBytes = writtenBytes;
257
+ this.totalWrittenBytes = totalWrittenBytes;
258
+ }
259
+ }
260
+
261
+ export class FileSaveResult {
262
+ readonly fileName: string;
263
+ readonly mode: FileSaveMode;
264
+ readonly writtenBytes: u64;
265
+
266
+ constructor(fileName: string, mode: FileSaveMode, writtenBytes: u64) {
267
+ this.fileName = fileName;
268
+ this.mode = mode;
269
+ this.writtenBytes = writtenBytes;
270
+ }
271
+ }
272
+
273
+ export class FileWorkerProcessProgress {
274
+ readonly processedBytes: u64;
275
+ readonly totalBytes: u64;
276
+ readonly outputFileName: string | null;
277
+
278
+ constructor(processedBytes: u64, totalBytes: u64, outputFileName: string | null) {
279
+ this.processedBytes = processedBytes;
280
+ this.totalBytes = totalBytes;
281
+ this.outputFileName = outputFileName;
282
+ }
283
+ }
284
+
285
+ export class FileWorkerProcessResult {
286
+ readonly processedBytes: u64;
287
+ readonly outputFileName: string | null;
288
+
289
+ constructor(processedBytes: u64, outputFileName: string | null) {
290
+ this.processedBytes = processedBytes;
291
+ this.outputFileName = outputFileName;
292
+ }
293
+ }
294
+
295
+ export class BrowserFile {
296
+ readonly id: string;
297
+ name: string;
298
+ mimeType: string | null;
299
+ sizeBytes: u64;
300
+ lastModifiedMs: u64;
301
+
302
+ constructor(id: string, name: string, mimeType: string | null, sizeBytes: u64, lastModifiedMs: u64 = 0) {
303
+ this.id = id;
304
+ this.name = name;
305
+ this.mimeType = mimeType;
306
+ this.sizeBytes = sizeBytes;
307
+ this.lastModifiedMs = lastModifiedMs;
308
+ }
309
+
310
+ readBytesChunkWith<Owner>(
311
+ owner: Owner,
312
+ offsetBytes: u64,
313
+ maxBytes: u32,
314
+ handler: Handler1<Owner, FileReadChunk>,
315
+ errorHandler: Handler1<Owner, string> | null = null,
316
+ ): Disposable {
317
+ if (changetype<usize>(handler) == 0) {
318
+ throwNullArgument(FUNCTION_READ_BYTES_CHUNK_WITH, "handler");
319
+ }
320
+ if (maxBytes == 0) {
321
+ dispatchFileError(
322
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
323
+ "BrowserFile.readBytesChunkWith: maxBytes must be greater than zero.",
324
+ );
325
+ return new FileRequestDisposable(REQUEST_KIND_READ, 0);
326
+ }
327
+ const fileIdBytes = encodeUtf8(this.id);
328
+ const requestId = registerPendingReadRequest(new PendingReadRequest(
329
+ bind1<Owner, FileReadChunk>(owner, handler),
330
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
331
+ ));
332
+ fui_file_read_chunk(
333
+ requestId,
334
+ fileIdBytes.length > 0 ? fileIdBytes.dataStart : 0,
335
+ <u32>fileIdBytes.length,
336
+ offsetBytes,
337
+ maxBytes,
338
+ );
339
+ return new FileRequestDisposable(REQUEST_KIND_READ, requestId);
340
+ }
341
+ }
342
+
343
+ export class FileWorkerProcessRequest implements Disposable {
344
+ private readonly file: BrowserFile;
345
+ private suggestedNameValue: string;
346
+ private saveToPickedFileEnabled: bool = false;
347
+ private chunkBytesValue: u32 = 64 * 1024;
348
+ private chunkBinding: Callback1<FileReadChunk> | null = null;
349
+ private progressBinding: Callback1<FileWorkerProcessProgress> | null = null;
350
+ private completeBinding: Callback1<FileWorkerProcessResult> | null = null;
351
+ private errorBinding: Callback1<string> | null = null;
352
+ private requestId: u32 = 0;
353
+ private started: bool = false;
354
+ private finished: bool = false;
355
+
356
+ constructor(file: BrowserFile) {
357
+ this.file = file;
358
+ this.suggestedNameValue = file.name;
359
+ }
360
+
361
+ suggestedName(value: string): this {
362
+ if (changetype<usize>(value) == 0) {
363
+ throwNullArgument("FileWorkerProcessRequest.suggestedName", "value");
364
+ }
365
+ this.suggestedNameValue = value;
366
+ return this;
367
+ }
368
+
369
+ saveToPickedFile(value: string): this {
370
+ this.saveToPickedFileEnabled = true;
371
+ return this.suggestedName(value);
372
+ }
373
+
374
+ chunkBytes(value: u32): this {
375
+ this.chunkBytesValue = value;
376
+ return this;
377
+ }
378
+
379
+ onChunk<Owner>(owner: Owner, handler: Handler1<Owner, FileReadChunk>): this {
380
+ if (changetype<usize>(handler) == 0) {
381
+ throwNullArgument("FileWorkerProcessRequest.onChunk", "handler");
382
+ }
383
+ this.chunkBinding = bind1<Owner, FileReadChunk>(owner, handler);
384
+ return this;
385
+ }
386
+
387
+ onChunkWith<Owner>(owner: Owner, handler: Handler1<Owner, FileReadChunk>): this {
388
+ return this.onChunk<Owner>(owner, handler);
389
+ }
390
+
391
+ onProgress<Owner>(owner: Owner, handler: Handler1<Owner, FileWorkerProcessProgress>): this {
392
+ if (changetype<usize>(handler) == 0) {
393
+ throwNullArgument("FileWorkerProcessRequest.onProgress", "handler");
394
+ }
395
+ this.progressBinding = bind1<Owner, FileWorkerProcessProgress>(owner, handler);
396
+ return this;
397
+ }
398
+
399
+ onProgressWith<Owner>(owner: Owner, handler: Handler1<Owner, FileWorkerProcessProgress>): this {
400
+ return this.onProgress<Owner>(owner, handler);
401
+ }
402
+
403
+ onComplete<Owner>(owner: Owner, handler: Handler1<Owner, FileWorkerProcessResult>): this {
404
+ if (changetype<usize>(handler) == 0) {
405
+ throwNullArgument("FileWorkerProcessRequest.onComplete", "handler");
406
+ }
407
+ this.completeBinding = bind1<Owner, FileWorkerProcessResult>(owner, handler);
408
+ return this;
409
+ }
410
+
411
+ onCompleteWith<Owner>(owner: Owner, handler: Handler1<Owner, FileWorkerProcessResult>): this {
412
+ return this.onComplete<Owner>(owner, handler);
413
+ }
414
+
415
+ onError<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
416
+ if (changetype<usize>(handler) == 0) {
417
+ throwNullArgument("FileWorkerProcessRequest.onError", "handler");
418
+ }
419
+ this.errorBinding = bind1<Owner, string>(owner, handler);
420
+ return this;
421
+ }
422
+
423
+ onErrorWith<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
424
+ return this.onError<Owner>(owner, handler);
425
+ }
426
+
427
+ start(): this {
428
+ if (this.finished) {
429
+ warn("File", "FileWorkerProcessRequest.start ignored after the worker process already finished.");
430
+ return this;
431
+ }
432
+ if (this.started) {
433
+ warn("File", "FileWorkerProcessRequest.start ignored because the request already started.");
434
+ return this;
435
+ }
436
+ if (this.chunkBytesValue == 0) {
437
+ dispatchFileError(this.errorBinding, "FileWorkerProcessRequest.start: chunkBytes must be greater than zero.");
438
+ return this;
439
+ }
440
+ if (!this.saveToPickedFileEnabled && this.chunkBinding === null) {
441
+ dispatchFileError(this.errorBinding, "FileWorkerProcessRequest.start: either saveToPickedFile(...) or onChunk(...) is required.");
442
+ return this;
443
+ }
444
+ const fileIdBytes = encodeUtf8(this.file.id);
445
+ const suggestedNameBytes = encodeUtf8(this.suggestedNameValue);
446
+ this.requestId = registerPendingWorkerProcessRequest(this);
447
+ this.started = true;
448
+ fui_file_process_worker_start(
449
+ this.requestId,
450
+ fileIdBytes.length > 0 ? fileIdBytes.dataStart : 0,
451
+ <u32>fileIdBytes.length,
452
+ suggestedNameBytes.length > 0 ? suggestedNameBytes.dataStart : 0,
453
+ <u32>suggestedNameBytes.length,
454
+ this.chunkBytesValue,
455
+ this.saveToPickedFileEnabled,
456
+ );
457
+ return this;
458
+ }
459
+
460
+ cancel(): void {
461
+ this.dispose();
462
+ }
463
+
464
+ dispose(): void {
465
+ if (this.finished) {
466
+ return;
467
+ }
468
+ if (this.requestId != 0) {
469
+ const requestId = this.requestId;
470
+ this.requestId = 0;
471
+ pendingWorkerProcessRequests.delete(requestId);
472
+ fui_file_process_worker_cancel(requestId);
473
+ }
474
+ this.finished = true;
475
+ this.chunkBinding = null;
476
+ this.progressBinding = null;
477
+ this.completeBinding = null;
478
+ this.errorBinding = null;
479
+ }
480
+
481
+ dispatchChunk(chunk: FileReadChunk): void {
482
+ if (this.finished) {
483
+ return;
484
+ }
485
+ const binding = this.chunkBinding;
486
+ if (binding !== null) {
487
+ binding.invoke(chunk);
488
+ }
489
+ }
490
+
491
+ dispatchProgress(progress: FileWorkerProcessProgress): void {
492
+ if (this.finished) {
493
+ return;
494
+ }
495
+ const binding = this.progressBinding;
496
+ if (binding !== null) {
497
+ binding.invoke(progress);
498
+ }
499
+ }
500
+
501
+ dispatchComplete(result: FileWorkerProcessResult): void {
502
+ if (this.finished) {
503
+ return;
504
+ }
505
+ const binding = this.completeBinding;
506
+ this.finish();
507
+ if (binding !== null) {
508
+ binding.invoke(result);
509
+ }
510
+ }
511
+
512
+ dispatchError(status: u32, message: string | null = null): void {
513
+ if (this.finished) {
514
+ return;
515
+ }
516
+ const binding = this.errorBinding;
517
+ this.finish();
518
+ dispatchFileError(binding, message === null ? describeFileFailure(status, "Worker file processing failed.") : message);
519
+ }
520
+
521
+ private finish(): void {
522
+ const requestId = this.requestId;
523
+ this.requestId = 0;
524
+ if (requestId != 0) {
525
+ pendingWorkerProcessRequests.delete(requestId);
526
+ }
527
+ this.started = false;
528
+ this.finished = true;
529
+ this.chunkBinding = null;
530
+ this.progressBinding = null;
531
+ this.completeBinding = null;
532
+ this.errorBinding = null;
533
+ }
534
+ }
535
+
536
+ export class BrowserFileWriter {
537
+ readonly fileName: string;
538
+ readonly mode: FileSaveMode;
539
+ private readonly writerId: string;
540
+
541
+ constructor(writerId: string, fileName: string, mode: FileSaveMode) {
542
+ this.writerId = writerId;
543
+ this.fileName = fileName;
544
+ this.mode = mode;
545
+ }
546
+
547
+ writeTextChunkWith<Owner>(
548
+ owner: Owner,
549
+ text: string,
550
+ handler: Handler1<Owner, FileWriteProgress>,
551
+ errorHandler: Handler1<Owner, string> | null = null,
552
+ ): Disposable {
553
+ if (changetype<usize>(text) == 0) {
554
+ throwNullArgument(FUNCTION_WRITE_TEXT_CHUNK_WITH, "text");
555
+ }
556
+ if (changetype<usize>(handler) == 0) {
557
+ throwNullArgument(FUNCTION_WRITE_TEXT_CHUNK_WITH, "handler");
558
+ }
559
+ const writerIdBytes = encodeUtf8(this.writerId);
560
+ const textBytes = encodeUtf8(text);
561
+ const requestId = registerPendingWriterWriteRequest(new PendingWriterWriteRequest(
562
+ bind1<Owner, FileWriteProgress>(owner, handler),
563
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
564
+ ));
565
+ fui_file_writer_write_text(
566
+ requestId,
567
+ writerIdBytes.length > 0 ? writerIdBytes.dataStart : 0,
568
+ <u32>writerIdBytes.length,
569
+ textBytes.length > 0 ? textBytes.dataStart : 0,
570
+ <u32>textBytes.length,
571
+ );
572
+ return new FileRequestDisposable(REQUEST_KIND_WRITE, requestId);
573
+ }
574
+
575
+ writeBytesChunkWith<Owner>(
576
+ owner: Owner,
577
+ bytes: Uint8Array,
578
+ handler: Handler1<Owner, FileWriteProgress>,
579
+ errorHandler: Handler1<Owner, string> | null = null,
580
+ ): Disposable {
581
+ if (changetype<usize>(bytes) == 0) {
582
+ throwNullArgument(FUNCTION_WRITE_BYTES_CHUNK_WITH, "bytes");
583
+ }
584
+ if (changetype<usize>(handler) == 0) {
585
+ throwNullArgument(FUNCTION_WRITE_BYTES_CHUNK_WITH, "handler");
586
+ }
587
+ const writerIdBytes = encodeUtf8(this.writerId);
588
+ const requestId = registerPendingWriterWriteRequest(new PendingWriterWriteRequest(
589
+ bind1<Owner, FileWriteProgress>(owner, handler),
590
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
591
+ ));
592
+ fui_file_writer_write_bytes(
593
+ requestId,
594
+ writerIdBytes.length > 0 ? writerIdBytes.dataStart : 0,
595
+ <u32>writerIdBytes.length,
596
+ bytes.length > 0 ? bytes.dataStart : 0,
597
+ <u32>bytes.length,
598
+ );
599
+ return new FileRequestDisposable(REQUEST_KIND_WRITE, requestId);
600
+ }
601
+
602
+ finishWith<Owner>(
603
+ owner: Owner,
604
+ handler: Handler1<Owner, FileSaveResult>,
605
+ errorHandler: Handler1<Owner, string> | null = null,
606
+ ): Disposable {
607
+ if (changetype<usize>(handler) == 0) {
608
+ throwNullArgument(FUNCTION_FINISH_WITH, "handler");
609
+ }
610
+ const writerIdBytes = encodeUtf8(this.writerId);
611
+ const requestId = registerPendingWriterFinishRequest(new PendingWriterFinishRequest(
612
+ bind1<Owner, FileSaveResult>(owner, handler),
613
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
614
+ ));
615
+ fui_file_writer_finish(
616
+ requestId,
617
+ writerIdBytes.length > 0 ? writerIdBytes.dataStart : 0,
618
+ <u32>writerIdBytes.length,
619
+ );
620
+ return new FileRequestDisposable(REQUEST_KIND_FINISH, requestId);
621
+ }
622
+ }
623
+
624
+ export class FileOpenRequest {
625
+ private acceptValue: string = "";
626
+ private multipleValue: bool = false;
627
+
628
+ accept(value: string): this {
629
+ if (changetype<usize>(value) == 0) {
630
+ throwNullArgument("FileOpenRequest.accept", "value");
631
+ }
632
+ this.acceptValue = value;
633
+ return this;
634
+ }
635
+
636
+ multiple(flag: bool = true): this {
637
+ this.multipleValue = flag;
638
+ return this;
639
+ }
640
+
641
+ pickWith<Owner>(
642
+ owner: Owner,
643
+ handler: Handler1<Owner, Array<BrowserFile>>,
644
+ errorHandler: Handler1<Owner, string> | null = null,
645
+ ): Disposable {
646
+ if (changetype<usize>(handler) == 0) {
647
+ throwNullArgument(FUNCTION_PICK_WITH, "handler");
648
+ }
649
+ const acceptBytes = encodeUtf8(this.acceptValue);
650
+ const requestId = registerPendingOpenRequest(new PendingOpenRequest(
651
+ bind1<Owner, Array<BrowserFile>>(owner, handler),
652
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
653
+ ));
654
+ fui_file_pick(
655
+ requestId,
656
+ acceptBytes.length > 0 ? acceptBytes.dataStart : 0,
657
+ <u32>acceptBytes.length,
658
+ this.multipleValue,
659
+ );
660
+ return new FileRequestDisposable(REQUEST_KIND_OPEN, requestId);
661
+ }
662
+ }
663
+
664
+ export class FileSaveRequest {
665
+ private suggestedNameValue: string = "";
666
+ private mimeTypeValue: string = "";
667
+ private fileExtensionValue: string = "";
668
+
669
+ suggestedName(value: string): this {
670
+ if (changetype<usize>(value) == 0) {
671
+ throwNullArgument("FileSaveRequest.suggestedName", "value");
672
+ }
673
+ this.suggestedNameValue = value;
674
+ return this;
675
+ }
676
+
677
+ mimeType(value: string): this {
678
+ if (changetype<usize>(value) == 0) {
679
+ throwNullArgument("FileSaveRequest.mimeType", "value");
680
+ }
681
+ this.mimeTypeValue = value;
682
+ return this;
683
+ }
684
+
685
+ fileExtension(value: string): this {
686
+ if (changetype<usize>(value) == 0) {
687
+ throwNullArgument("FileSaveRequest.fileExtension", "value");
688
+ }
689
+ this.fileExtensionValue = value;
690
+ return this;
691
+ }
692
+
693
+ saveTextWith<Owner>(
694
+ owner: Owner,
695
+ text: string,
696
+ handler: Handler1<Owner, FileSaveResult>,
697
+ errorHandler: Handler1<Owner, string> | null = null,
698
+ ): Disposable {
699
+ if (changetype<usize>(text) == 0) {
700
+ throwNullArgument(FUNCTION_SAVE_TEXT_WITH, "text");
701
+ }
702
+ if (changetype<usize>(handler) == 0) {
703
+ throwNullArgument(FUNCTION_SAVE_TEXT_WITH, "handler");
704
+ }
705
+ const suggestedNameBytes = encodeUtf8(this.suggestedNameValue);
706
+ const mimeTypeBytes = encodeUtf8(this.mimeTypeValue);
707
+ const extensionBytes = encodeUtf8(this.fileExtensionValue);
708
+ const textBytes = encodeUtf8(text);
709
+ const requestId = registerPendingSaveRequest(new PendingSaveRequest(
710
+ bind1<Owner, FileSaveResult>(owner, handler),
711
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
712
+ ));
713
+ fui_file_save_text(
714
+ requestId,
715
+ suggestedNameBytes.length > 0 ? suggestedNameBytes.dataStart : 0,
716
+ <u32>suggestedNameBytes.length,
717
+ mimeTypeBytes.length > 0 ? mimeTypeBytes.dataStart : 0,
718
+ <u32>mimeTypeBytes.length,
719
+ extensionBytes.length > 0 ? extensionBytes.dataStart : 0,
720
+ <u32>extensionBytes.length,
721
+ textBytes.length > 0 ? textBytes.dataStart : 0,
722
+ <u32>textBytes.length,
723
+ );
724
+ return new FileRequestDisposable(REQUEST_KIND_SAVE, requestId);
725
+ }
726
+
727
+ saveBytesWith<Owner>(
728
+ owner: Owner,
729
+ bytes: Uint8Array,
730
+ handler: Handler1<Owner, FileSaveResult>,
731
+ errorHandler: Handler1<Owner, string> | null = null,
732
+ ): Disposable {
733
+ if (changetype<usize>(bytes) == 0) {
734
+ throwNullArgument(FUNCTION_SAVE_BYTES_WITH, "bytes");
735
+ }
736
+ if (changetype<usize>(handler) == 0) {
737
+ throwNullArgument(FUNCTION_SAVE_BYTES_WITH, "handler");
738
+ }
739
+ const suggestedNameBytes = encodeUtf8(this.suggestedNameValue);
740
+ const mimeTypeBytes = encodeUtf8(this.mimeTypeValue);
741
+ const extensionBytes = encodeUtf8(this.fileExtensionValue);
742
+ const requestId = registerPendingSaveRequest(new PendingSaveRequest(
743
+ bind1<Owner, FileSaveResult>(owner, handler),
744
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
745
+ ));
746
+ fui_file_save_bytes(
747
+ requestId,
748
+ suggestedNameBytes.length > 0 ? suggestedNameBytes.dataStart : 0,
749
+ <u32>suggestedNameBytes.length,
750
+ mimeTypeBytes.length > 0 ? mimeTypeBytes.dataStart : 0,
751
+ <u32>mimeTypeBytes.length,
752
+ extensionBytes.length > 0 ? extensionBytes.dataStart : 0,
753
+ <u32>extensionBytes.length,
754
+ bytes.length > 0 ? bytes.dataStart : 0,
755
+ <u32>bytes.length,
756
+ );
757
+ return new FileRequestDisposable(REQUEST_KIND_SAVE, requestId);
758
+ }
759
+
760
+ createWriterWith<Owner>(
761
+ owner: Owner,
762
+ handler: Handler1<Owner, BrowserFileWriter>,
763
+ errorHandler: Handler1<Owner, string> | null = null,
764
+ ): Disposable {
765
+ if (changetype<usize>(handler) == 0) {
766
+ throwNullArgument(FUNCTION_CREATE_WRITER_WITH, "handler");
767
+ }
768
+ const suggestedNameBytes = encodeUtf8(this.suggestedNameValue);
769
+ const mimeTypeBytes = encodeUtf8(this.mimeTypeValue);
770
+ const extensionBytes = encodeUtf8(this.fileExtensionValue);
771
+ const requestId = registerPendingWriterCreateRequest(new PendingWriterCreateRequest(
772
+ bind1<Owner, BrowserFileWriter>(owner, handler),
773
+ errorHandler === null ? null : bind1<Owner, string>(owner, errorHandler),
774
+ ));
775
+ fui_file_create_writer(
776
+ requestId,
777
+ suggestedNameBytes.length > 0 ? suggestedNameBytes.dataStart : 0,
778
+ <u32>suggestedNameBytes.length,
779
+ mimeTypeBytes.length > 0 ? mimeTypeBytes.dataStart : 0,
780
+ <u32>mimeTypeBytes.length,
781
+ extensionBytes.length > 0 ? extensionBytes.dataStart : 0,
782
+ <u32>extensionBytes.length,
783
+ );
784
+ return new FileRequestDisposable(REQUEST_KIND_CREATE_WRITER, requestId);
785
+ }
786
+ }
787
+
788
+ export class File {
789
+ static open(): FileOpenRequest {
790
+ return new FileOpenRequest();
791
+ }
792
+
793
+ static save(): FileSaveRequest {
794
+ return new FileSaveRequest();
795
+ }
796
+
797
+ static processFileInWorker(file: BrowserFile): FileWorkerProcessRequest {
798
+ if (changetype<usize>(file) == 0) {
799
+ throwNullArgument(FUNCTION_FILE_WORKER_PROCESS_START, "file");
800
+ }
801
+ return new FileWorkerProcessRequest(file);
802
+ }
803
+
804
+ static capabilities(): FileCapabilities {
805
+ return new FileCapabilities(fui_file_capabilities());
806
+ }
807
+
808
+ static tryGetFile(id: string): BrowserFile | null {
809
+ if (browserFiles.has(id)) {
810
+ return unchecked(browserFiles.get(id));
811
+ }
812
+ return null;
813
+ }
814
+ }
815
+
816
+ export function registerBrowserFile(
817
+ id: string,
818
+ name: string,
819
+ mimeType: string | null,
820
+ sizeBytes: u64,
821
+ lastModifiedMs: u64 = 0,
822
+ ): BrowserFile {
823
+ if (browserFiles.has(id)) {
824
+ const existing = unchecked(browserFiles.get(id));
825
+ existing.name = name;
826
+ existing.mimeType = mimeType;
827
+ existing.sizeBytes = sizeBytes;
828
+ existing.lastModifiedMs = lastModifiedMs;
829
+ return existing;
830
+ }
831
+ const file = new BrowserFile(id, name, mimeType, sizeBytes, lastModifiedMs);
832
+ browserFiles.set(id, file);
833
+ return file;
834
+ }
835
+
836
+ export function handleFilePickResult(requestId: u32, status: u32, files: Array<BrowserFile>, message: string | null = null): void {
837
+ const request = pendingOpenRequests.has(requestId) ? unchecked(pendingOpenRequests.get(requestId)) : null;
838
+ pendingOpenRequests.delete(requestId);
839
+ if (request === null) {
840
+ return;
841
+ }
842
+ if (status == FILE_STATUS_SUCCESS) {
843
+ request.completeBinding.invoke(files);
844
+ return;
845
+ }
846
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "File picker failed.") : message);
847
+ }
848
+
849
+ export function handleFileReadChunkResult(
850
+ requestId: u32,
851
+ status: u32,
852
+ chunk: FileReadChunk | null,
853
+ message: string | null = null,
854
+ ): void {
855
+ const request = pendingReadRequests.has(requestId) ? unchecked(pendingReadRequests.get(requestId)) : null;
856
+ pendingReadRequests.delete(requestId);
857
+ if (request === null) {
858
+ return;
859
+ }
860
+ if (status == FILE_STATUS_SUCCESS && chunk !== null) {
861
+ request.completeBinding.invoke(chunk);
862
+ return;
863
+ }
864
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "File read failed.") : message);
865
+ }
866
+
867
+ export function handleFileSaveResult(
868
+ requestId: u32,
869
+ status: u32,
870
+ result: FileSaveResult | null,
871
+ message: string | null = null,
872
+ ): void {
873
+ const request = pendingSaveRequests.has(requestId) ? unchecked(pendingSaveRequests.get(requestId)) : null;
874
+ pendingSaveRequests.delete(requestId);
875
+ if (request === null) {
876
+ return;
877
+ }
878
+ if (status == FILE_STATUS_SUCCESS && result !== null) {
879
+ request.completeBinding.invoke(result);
880
+ return;
881
+ }
882
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "File save failed.") : message);
883
+ }
884
+
885
+ export function handleFileWriterCreated(
886
+ requestId: u32,
887
+ status: u32,
888
+ writer: BrowserFileWriter | null,
889
+ message: string | null = null,
890
+ ): void {
891
+ const request = pendingWriterCreateRequests.has(requestId) ? unchecked(pendingWriterCreateRequests.get(requestId)) : null;
892
+ pendingWriterCreateRequests.delete(requestId);
893
+ if (request === null) {
894
+ return;
895
+ }
896
+ if (status == FILE_STATUS_SUCCESS && writer !== null) {
897
+ request.completeBinding.invoke(writer);
898
+ return;
899
+ }
900
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "Creating a file writer failed.") : message);
901
+ }
902
+
903
+ export function handleFileWriterProgress(
904
+ requestId: u32,
905
+ status: u32,
906
+ progress: FileWriteProgress | null,
907
+ message: string | null = null,
908
+ ): void {
909
+ const request = pendingWriterWriteRequests.has(requestId) ? unchecked(pendingWriterWriteRequests.get(requestId)) : null;
910
+ pendingWriterWriteRequests.delete(requestId);
911
+ if (request === null) {
912
+ return;
913
+ }
914
+ if (status == FILE_STATUS_SUCCESS && progress !== null) {
915
+ request.completeBinding.invoke(progress);
916
+ return;
917
+ }
918
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "File write failed.") : message);
919
+ }
920
+
921
+ export function handleFileWriterFinished(
922
+ requestId: u32,
923
+ status: u32,
924
+ result: FileSaveResult | null,
925
+ message: string | null = null,
926
+ ): void {
927
+ const request = pendingWriterFinishRequests.has(requestId) ? unchecked(pendingWriterFinishRequests.get(requestId)) : null;
928
+ pendingWriterFinishRequests.delete(requestId);
929
+ if (request === null) {
930
+ return;
931
+ }
932
+ if (status == FILE_STATUS_SUCCESS && result !== null) {
933
+ request.completeBinding.invoke(result);
934
+ return;
935
+ }
936
+ dispatchFileError(request.errorBinding, message === null ? describeFileFailure(status, "Finishing the file writer failed.") : message);
937
+ }
938
+
939
+ export function handleFileWorkerProcessProgress(
940
+ requestId: u32,
941
+ processedBytes: u64,
942
+ totalBytes: u64,
943
+ outputFileName: string | null,
944
+ ): void {
945
+ const request = pendingWorkerProcessRequests.has(requestId) ? unchecked(pendingWorkerProcessRequests.get(requestId)) : null;
946
+ if (request === null) {
947
+ return;
948
+ }
949
+ request.dispatchProgress(new FileWorkerProcessProgress(processedBytes, totalBytes, outputFileName));
950
+ }
951
+
952
+ export function handleFileWorkerProcessChunk(requestId: u32, chunk: FileReadChunk | null): void {
953
+ const request = pendingWorkerProcessRequests.has(requestId) ? unchecked(pendingWorkerProcessRequests.get(requestId)) : null;
954
+ if (request === null || chunk === null) {
955
+ return;
956
+ }
957
+ request.dispatchChunk(chunk);
958
+ }
959
+
960
+ export function handleFileWorkerProcessComplete(
961
+ requestId: u32,
962
+ processedBytes: u64,
963
+ outputFileName: string | null,
964
+ ): void {
965
+ const request = pendingWorkerProcessRequests.has(requestId) ? unchecked(pendingWorkerProcessRequests.get(requestId)) : null;
966
+ if (request === null) {
967
+ return;
968
+ }
969
+ request.dispatchComplete(new FileWorkerProcessResult(processedBytes, outputFileName));
970
+ }
971
+
972
+ export function handleFileWorkerProcessError(requestId: u32, status: u32, message: string | null = null): void {
973
+ const request = pendingWorkerProcessRequests.has(requestId) ? unchecked(pendingWorkerProcessRequests.get(requestId)) : null;
974
+ if (request === null) {
975
+ return;
976
+ }
977
+ request.dispatchError(status, message);
978
+ }
979
+
980
+ export function createBrowserFileWriter(writerId: string, fileName: string, mode: FileSaveMode): BrowserFileWriter {
981
+ return new BrowserFileWriter(writerId, fileName, mode);
982
+ }
983
+
984
+ export function disposeAllFileRequests(): void {
985
+ const workerProcessRequests = pendingWorkerProcessRequests.values();
986
+ for (let index = 0; index < workerProcessRequests.length; ++index) {
987
+ unchecked(workerProcessRequests[index]).dispose();
988
+ }
989
+ pendingOpenRequests.clear();
990
+ pendingReadRequests.clear();
991
+ pendingSaveRequests.clear();
992
+ pendingWriterCreateRequests.clear();
993
+ pendingWriterWriteRequests.clear();
994
+ pendingWriterFinishRequests.clear();
995
+ pendingWorkerProcessRequests.clear();
996
+ }
997
+
998
+ export function __resetFileForTests(): void {
999
+ disposeAllFileRequests();
1000
+ browserFiles.clear();
1001
+ nextFileRequestId = 1;
1002
+ }