@livestore/sqlite-wasm 0.4.0-dev.3 → 0.4.0-dev.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/browser/mod.d.ts +1 -0
  3. package/dist/browser/mod.d.ts.map +1 -1
  4. package/dist/browser/mod.js.map +1 -1
  5. package/dist/browser/opfs/AccessHandlePoolVFS.d.ts +7 -0
  6. package/dist/browser/opfs/AccessHandlePoolVFS.d.ts.map +1 -1
  7. package/dist/browser/opfs/AccessHandlePoolVFS.js +36 -1
  8. package/dist/browser/opfs/AccessHandlePoolVFS.js.map +1 -1
  9. package/dist/cf/BlockManager.d.ts +61 -0
  10. package/dist/cf/BlockManager.d.ts.map +1 -0
  11. package/dist/cf/BlockManager.js +157 -0
  12. package/dist/cf/BlockManager.js.map +1 -0
  13. package/dist/cf/CloudflareSqlVFS.d.ts +51 -0
  14. package/dist/cf/CloudflareSqlVFS.d.ts.map +1 -0
  15. package/dist/cf/CloudflareSqlVFS.js +351 -0
  16. package/dist/cf/CloudflareSqlVFS.js.map +1 -0
  17. package/dist/cf/CloudflareWorkerVFS.d.ts +72 -0
  18. package/dist/cf/CloudflareWorkerVFS.d.ts.map +1 -0
  19. package/dist/cf/CloudflareWorkerVFS.js +552 -0
  20. package/dist/cf/CloudflareWorkerVFS.js.map +1 -0
  21. package/dist/cf/mod.d.ts +43 -0
  22. package/dist/cf/mod.d.ts.map +1 -0
  23. package/dist/cf/mod.js +74 -0
  24. package/dist/cf/mod.js.map +1 -0
  25. package/dist/cf/test/async-storage/cloudflare-worker-vfs-advanced.test.d.ts +2 -0
  26. package/dist/cf/test/async-storage/cloudflare-worker-vfs-advanced.test.d.ts.map +1 -0
  27. package/dist/cf/test/async-storage/cloudflare-worker-vfs-advanced.test.js +314 -0
  28. package/dist/cf/test/async-storage/cloudflare-worker-vfs-advanced.test.js.map +1 -0
  29. package/dist/cf/test/async-storage/cloudflare-worker-vfs-core.test.d.ts +2 -0
  30. package/dist/cf/test/async-storage/cloudflare-worker-vfs-core.test.d.ts.map +1 -0
  31. package/dist/cf/test/async-storage/cloudflare-worker-vfs-core.test.js +266 -0
  32. package/dist/cf/test/async-storage/cloudflare-worker-vfs-core.test.js.map +1 -0
  33. package/dist/cf/test/async-storage/cloudflare-worker-vfs-integration.test.d.ts +2 -0
  34. package/dist/cf/test/async-storage/cloudflare-worker-vfs-integration.test.d.ts.map +1 -0
  35. package/dist/cf/test/async-storage/cloudflare-worker-vfs-integration.test.js +444 -0
  36. package/dist/cf/test/async-storage/cloudflare-worker-vfs-integration.test.js.map +1 -0
  37. package/dist/cf/test/async-storage/cloudflare-worker-vfs-reliability.test.d.ts +2 -0
  38. package/dist/cf/test/async-storage/cloudflare-worker-vfs-reliability.test.d.ts.map +1 -0
  39. package/dist/cf/test/async-storage/cloudflare-worker-vfs-reliability.test.js +334 -0
  40. package/dist/cf/test/async-storage/cloudflare-worker-vfs-reliability.test.js.map +1 -0
  41. package/dist/cf/test/sql/cloudflare-sql-vfs-core.test.d.ts +2 -0
  42. package/dist/cf/test/sql/cloudflare-sql-vfs-core.test.d.ts.map +1 -0
  43. package/dist/cf/test/sql/cloudflare-sql-vfs-core.test.js +354 -0
  44. package/dist/cf/test/sql/cloudflare-sql-vfs-core.test.js.map +1 -0
  45. package/dist/load-wasm/mod.node.d.ts.map +1 -1
  46. package/dist/load-wasm/mod.node.js +1 -2
  47. package/dist/load-wasm/mod.node.js.map +1 -1
  48. package/dist/load-wasm/mod.workerd.d.ts +2 -0
  49. package/dist/load-wasm/mod.workerd.d.ts.map +1 -0
  50. package/dist/load-wasm/mod.workerd.js +26 -0
  51. package/dist/load-wasm/mod.workerd.js.map +1 -0
  52. package/dist/make-sqlite-db.d.ts +1 -0
  53. package/dist/make-sqlite-db.d.ts.map +1 -1
  54. package/dist/make-sqlite-db.js.map +1 -1
  55. package/dist/node/NodeFS.d.ts +1 -2
  56. package/dist/node/NodeFS.d.ts.map +1 -1
  57. package/dist/node/NodeFS.js +1 -6
  58. package/dist/node/NodeFS.js.map +1 -1
  59. package/dist/node/mod.js +3 -8
  60. package/dist/node/mod.js.map +1 -1
  61. package/package.json +20 -7
  62. package/src/browser/mod.ts +1 -0
  63. package/src/browser/opfs/AccessHandlePoolVFS.ts +37 -1
  64. package/src/cf/BlockManager.ts +225 -0
  65. package/src/cf/CloudflareSqlVFS.ts +450 -0
  66. package/src/cf/CloudflareWorkerVFS.ts +664 -0
  67. package/src/cf/README.md +60 -0
  68. package/src/cf/mod.ts +143 -0
  69. package/src/cf/test/README.md +224 -0
  70. package/src/cf/test/async-storage/cloudflare-worker-vfs-advanced.test.ts +389 -0
  71. package/src/cf/test/async-storage/cloudflare-worker-vfs-core.test.ts +322 -0
  72. package/src/cf/test/async-storage/cloudflare-worker-vfs-integration.test.ts +567 -0
  73. package/src/cf/test/async-storage/cloudflare-worker-vfs-reliability.test.ts +403 -0
  74. package/src/cf/test/sql/cloudflare-sql-vfs-core.test.ts +433 -0
  75. package/src/load-wasm/mod.node.ts +1 -2
  76. package/src/load-wasm/mod.workerd.ts +26 -0
  77. package/src/make-sqlite-db.ts +1 -0
  78. package/src/node/NodeFS.ts +1 -9
  79. package/src/node/mod.ts +3 -10
@@ -0,0 +1,389 @@
1
+ /// <reference types="vitest/globals" />
2
+
3
+ import type { CfTypes } from '@livestore/common-cf'
4
+ import * as VFS from '@livestore/wa-sqlite/src/VFS.js'
5
+ import { beforeEach, describe, expect, it } from 'vitest'
6
+ import { CloudflareWorkerVFS } from '../../mod.ts'
7
+
8
+ describe('CloudflareWorkerVFS - Advanced Features', () => {
9
+ let vfs: CloudflareWorkerVFS
10
+ let mockStorage: CfTypes.DurableObjectStorage
11
+ let storageData: Map<string, any>
12
+
13
+ beforeEach(async () => {
14
+ storageData = new Map<string, any>()
15
+
16
+ mockStorage = {
17
+ get: (async (_key: string | string[]) => {
18
+ if (Array.isArray(_key)) {
19
+ return new Map()
20
+ }
21
+ return storageData.get(_key)
22
+ }) as CfTypes.DurableObjectStorage['get'],
23
+
24
+ put: async (_key: string | Record<string, any>, _value?: any) => {
25
+ if (typeof _key === 'string') {
26
+ storageData.set(_key, _value)
27
+ } else {
28
+ for (const [k, v] of Object.entries(_key)) {
29
+ storageData.set(k, v)
30
+ }
31
+ }
32
+ },
33
+
34
+ delete: (async (_key: string | string[]) => {
35
+ if (Array.isArray(_key)) {
36
+ let count = 0
37
+ for (const k of _key) {
38
+ if (storageData.delete(k)) count++
39
+ }
40
+ return count
41
+ } else {
42
+ return storageData.delete(_key)
43
+ }
44
+ }) as CfTypes.DurableObjectStorage['delete'],
45
+
46
+ list: async () => new Map(storageData),
47
+ sync: async () => {},
48
+ transactionSync: (fn: () => any) => fn(),
49
+ deleteAll: async () => {
50
+ storageData.clear()
51
+ },
52
+ transaction: async (fn: (txn: any) => Promise<any>) => fn({} as any),
53
+ getCurrentBookmark: async () => '',
54
+ getBookmarkForTime: async (_time: number | Date) => '',
55
+ onNextSessionRestoreBookmark: async (_bookmark: string) => '',
56
+ getAlarm: async () => null,
57
+ setAlarm: async (_timestamp: number | Date) => {},
58
+ deleteAlarm: async () => {},
59
+ sql: {} as any,
60
+ } as CfTypes.DurableObjectStorage
61
+
62
+ vfs = new CloudflareWorkerVFS('test-advanced-vfs', mockStorage, {})
63
+ await vfs.isReady()
64
+ })
65
+
66
+ describe('Large File Chunking', () => {
67
+ it('should handle large files with proper chunking', async () => {
68
+ const path = '/test/large-file.db'
69
+ const fileId = 1
70
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
71
+ const pOutFlags = new DataView(new ArrayBuffer(4))
72
+
73
+ vfs.jOpen(path, fileId, flags, pOutFlags)
74
+
75
+ // Write 5 chunks worth of data
76
+ const chunkSize = 64 * 1024
77
+ const numChunks = 5
78
+ const totalSize = chunkSize * numChunks
79
+ const largeData = new Uint8Array(totalSize)
80
+
81
+ // Fill with pattern for verification
82
+ for (let i = 0; i < totalSize; i++) {
83
+ largeData[i] = (i * 7) % 256
84
+ }
85
+
86
+ expect(vfs.jWrite(fileId, largeData, 0)).toBe(VFS.SQLITE_OK)
87
+
88
+ // Verify file size
89
+ const pSize64 = new DataView(new ArrayBuffer(8))
90
+ expect(vfs.jFileSize(fileId, pSize64)).toBe(VFS.SQLITE_OK)
91
+ expect(pSize64.getBigInt64(0, true)).toBe(BigInt(totalSize))
92
+
93
+ // Read back in chunks to verify chunking works correctly
94
+ for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
95
+ const chunkData = new Uint8Array(chunkSize)
96
+ const offset = chunkIdx * chunkSize
97
+
98
+ expect(vfs.jRead(fileId, chunkData, offset)).toBe(VFS.SQLITE_OK)
99
+ expect(chunkData).toEqual(largeData.slice(offset, offset + chunkSize))
100
+ }
101
+
102
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
103
+ })
104
+
105
+ it('should handle cross-chunk boundary operations', async () => {
106
+ const path = '/test/cross-chunk.db'
107
+ const fileId = 1
108
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
109
+ const pOutFlags = new DataView(new ArrayBuffer(4))
110
+
111
+ vfs.jOpen(path, fileId, flags, pOutFlags)
112
+
113
+ const chunkSize = 64 * 1024
114
+
115
+ // Write data spanning chunk boundaries
116
+ const spanData = new Uint8Array(chunkSize + 1000)
117
+ spanData.fill(0xaa)
118
+ const spanOffset = chunkSize - 500
119
+
120
+ expect(vfs.jWrite(fileId, spanData, spanOffset)).toBe(VFS.SQLITE_OK)
121
+
122
+ // Read back cross-boundary data
123
+ const readData = new Uint8Array(spanData.length)
124
+ expect(vfs.jRead(fileId, readData, spanOffset)).toBe(VFS.SQLITE_OK)
125
+ expect(readData).toEqual(spanData)
126
+
127
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
128
+ })
129
+ })
130
+
131
+ describe('Cache Management', () => {
132
+ it('should handle cache operations correctly', async () => {
133
+ const path = '/test/cache-test.db'
134
+ const fileId = 1
135
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
136
+ const pOutFlags = new DataView(new ArrayBuffer(4))
137
+
138
+ vfs.jOpen(path, fileId, flags, pOutFlags)
139
+
140
+ // Write data to populate cache
141
+ const testData = new TextEncoder().encode('Cache test data')
142
+ expect(vfs.jWrite(fileId, testData, 0)).toBe(VFS.SQLITE_OK)
143
+
144
+ // Multiple reads should use cache
145
+ for (let i = 0; i < 5; i++) {
146
+ const readData = new Uint8Array(testData.length)
147
+ expect(vfs.jRead(fileId, readData, 0)).toBe(VFS.SQLITE_OK)
148
+ expect(readData).toEqual(testData)
149
+ }
150
+
151
+ // Check cache statistics
152
+ const stats = vfs.getStats()
153
+ expect(stats.cachedChunks).toBeGreaterThan(0)
154
+ expect(stats.chunkSize).toBe(64 * 1024)
155
+
156
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
157
+ })
158
+
159
+ it('should handle large files that exceed cache capacity', async () => {
160
+ const path = '/test/cache-overflow.db'
161
+ const fileId = 1
162
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
163
+ const pOutFlags = new DataView(new ArrayBuffer(4))
164
+
165
+ vfs.jOpen(path, fileId, flags, pOutFlags)
166
+
167
+ // Write many chunks to potentially exceed cache
168
+ const chunkSize = 64 * 1024
169
+ const numChunks = 20 // Likely to exceed typical cache size
170
+
171
+ for (let i = 0; i < numChunks; i++) {
172
+ const chunkData = new Uint8Array(chunkSize)
173
+ chunkData.fill(i % 256)
174
+ const offset = i * chunkSize
175
+
176
+ expect(vfs.jWrite(fileId, chunkData, offset)).toBe(VFS.SQLITE_OK)
177
+ }
178
+
179
+ // Verify all chunks can still be read correctly
180
+ for (let i = 0; i < numChunks; i++) {
181
+ const readData = new Uint8Array(chunkSize)
182
+ const offset = i * chunkSize
183
+
184
+ const readResult = vfs.jRead(fileId, readData, offset)
185
+
186
+ if (readResult === VFS.SQLITE_OK) {
187
+ const expectedData = new Uint8Array(chunkSize)
188
+ expectedData.fill(i % 256)
189
+ expect(readData).toEqual(expectedData)
190
+ } else {
191
+ // Cache miss is acceptable for this test - we're testing cache pressure
192
+ expect(readResult).toBe(VFS.SQLITE_IOERR_SHORT_READ)
193
+ }
194
+ }
195
+
196
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
197
+ })
198
+ })
199
+
200
+ describe('SQLite File Types', () => {
201
+ it('should handle main database files', async () => {
202
+ const path = '/test/main.db'
203
+ const fileId = 1
204
+ const flags = VFS.SQLITE_OPEN_MAIN_DB | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
205
+ const pOutFlags = new DataView(new ArrayBuffer(4))
206
+
207
+ expect(vfs.jOpen(path, fileId, flags, pOutFlags)).toBe(VFS.SQLITE_OK)
208
+ expect(pOutFlags.getUint32(0, true)).toBe(flags)
209
+
210
+ // Write typical SQLite header
211
+ const header = new TextEncoder().encode('SQLite format 3\0')
212
+ expect(vfs.jWrite(fileId, header, 0)).toBe(VFS.SQLITE_OK)
213
+
214
+ // Read back header
215
+ const readHeader = new Uint8Array(header.length)
216
+ expect(vfs.jRead(fileId, readHeader, 0)).toBe(VFS.SQLITE_OK)
217
+ expect(readHeader).toEqual(header)
218
+
219
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
220
+ })
221
+
222
+ it('should handle WAL files', async () => {
223
+ const path = '/test/main.db-wal'
224
+ const fileId = 2
225
+ const flags = VFS.SQLITE_OPEN_WAL | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
226
+ const pOutFlags = new DataView(new ArrayBuffer(4))
227
+
228
+ expect(vfs.jOpen(path, fileId, flags, pOutFlags)).toBe(VFS.SQLITE_OK)
229
+
230
+ // Write WAL data
231
+ const walData = new Uint8Array(1000)
232
+ walData.fill(0xee)
233
+ expect(vfs.jWrite(fileId, walData, 0)).toBe(VFS.SQLITE_OK)
234
+
235
+ // Verify WAL data
236
+ const readWalData = new Uint8Array(walData.length)
237
+ expect(vfs.jRead(fileId, readWalData, 0)).toBe(VFS.SQLITE_OK)
238
+ expect(readWalData).toEqual(walData)
239
+
240
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
241
+ })
242
+
243
+ it('should handle journal files', async () => {
244
+ const path = '/test/main.db-journal'
245
+ const fileId = 3
246
+ const flags = VFS.SQLITE_OPEN_MAIN_JOURNAL | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
247
+ const pOutFlags = new DataView(new ArrayBuffer(4))
248
+
249
+ expect(vfs.jOpen(path, fileId, flags, pOutFlags)).toBe(VFS.SQLITE_OK)
250
+
251
+ // Write journal data
252
+ const journalData = new Uint8Array(500)
253
+ journalData.fill(0xff)
254
+ expect(vfs.jWrite(fileId, journalData, 0)).toBe(VFS.SQLITE_OK)
255
+
256
+ // Verify journal data
257
+ const readJournalData = new Uint8Array(journalData.length)
258
+ expect(vfs.jRead(fileId, readJournalData, 0)).toBe(VFS.SQLITE_OK)
259
+ expect(readJournalData).toEqual(journalData)
260
+
261
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
262
+ })
263
+
264
+ it('should handle temporary files', async () => {
265
+ const path = '/test/temp.db'
266
+ const fileId = 4
267
+ const flags = VFS.SQLITE_OPEN_TEMP_DB | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
268
+ const pOutFlags = new DataView(new ArrayBuffer(4))
269
+
270
+ expect(vfs.jOpen(path, fileId, flags, pOutFlags)).toBe(VFS.SQLITE_OK)
271
+
272
+ // Write temporary data
273
+ const tempData = new TextEncoder().encode('Temporary database content')
274
+ expect(vfs.jWrite(fileId, tempData, 0)).toBe(VFS.SQLITE_OK)
275
+
276
+ // Read temporary data
277
+ const readTempData = new Uint8Array(tempData.length)
278
+ expect(vfs.jRead(fileId, readTempData, 0)).toBe(VFS.SQLITE_OK)
279
+ expect(readTempData).toEqual(tempData)
280
+
281
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
282
+ })
283
+ })
284
+
285
+ describe('Advanced Operations', () => {
286
+ it('should handle multiple files with different types simultaneously', async () => {
287
+ const files = [
288
+ {
289
+ path: '/test/multi-main.db',
290
+ id: 1,
291
+ flags: VFS.SQLITE_OPEN_MAIN_DB | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE,
292
+ },
293
+ {
294
+ path: '/test/multi-main.db-wal',
295
+ id: 2,
296
+ flags: VFS.SQLITE_OPEN_WAL | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE,
297
+ },
298
+ {
299
+ path: '/test/multi-main.db-journal',
300
+ id: 3,
301
+ flags: VFS.SQLITE_OPEN_MAIN_JOURNAL | VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE,
302
+ },
303
+ ]
304
+
305
+ const pOutFlags = new DataView(new ArrayBuffer(4))
306
+
307
+ // Open all files
308
+ for (const file of files) {
309
+ expect(vfs.jOpen(file.path, file.id, file.flags, pOutFlags)).toBe(VFS.SQLITE_OK)
310
+ }
311
+
312
+ // Write different data to each file
313
+ for (let i = 0; i < files.length; i++) {
314
+ const data = new TextEncoder().encode(`File ${i} data`)
315
+ expect(vfs.jWrite(files[i]?.id ?? 0, data, 0)).toBe(VFS.SQLITE_OK)
316
+ }
317
+
318
+ // Verify each file has correct data
319
+ for (let i = 0; i < files.length; i++) {
320
+ const expected = new TextEncoder().encode(`File ${i} data`)
321
+ const actual = new Uint8Array(expected.length)
322
+ expect(vfs.jRead(files[i]?.id ?? 0, actual, 0)).toBe(VFS.SQLITE_OK)
323
+ expect(actual).toEqual(expected)
324
+ }
325
+
326
+ // Close all files
327
+ for (const file of files) {
328
+ expect(vfs.jClose(file.id)).toBe(VFS.SQLITE_OK)
329
+ }
330
+ })
331
+
332
+ it('should handle file truncation with chunking', async () => {
333
+ const path = '/test/truncate-chunks.db'
334
+ const fileId = 1
335
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
336
+ const pOutFlags = new DataView(new ArrayBuffer(4))
337
+
338
+ vfs.jOpen(path, fileId, flags, pOutFlags)
339
+
340
+ const chunkSize = 64 * 1024
341
+
342
+ // Write data spanning 3 chunks
343
+ const largeData = new Uint8Array(chunkSize * 3)
344
+ largeData.fill(0xdd)
345
+ expect(vfs.jWrite(fileId, largeData, 0)).toBe(VFS.SQLITE_OK)
346
+
347
+ // Truncate to 1.5 chunks
348
+ const truncateSize = chunkSize + chunkSize / 2
349
+ expect(vfs.jTruncate(fileId, truncateSize)).toBe(VFS.SQLITE_OK)
350
+
351
+ // Verify new size
352
+ const pSize64 = new DataView(new ArrayBuffer(8))
353
+ expect(vfs.jFileSize(fileId, pSize64)).toBe(VFS.SQLITE_OK)
354
+ expect(pSize64.getBigInt64(0, true)).toBe(BigInt(truncateSize))
355
+
356
+ // Verify data integrity after truncation
357
+ const readData = new Uint8Array(truncateSize)
358
+ expect(vfs.jRead(fileId, readData, 0)).toBe(VFS.SQLITE_OK)
359
+ expect(readData).toEqual(largeData.slice(0, truncateSize))
360
+
361
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
362
+ })
363
+
364
+ it('should handle sync operations with proper flush behavior', async () => {
365
+ const path = '/test/sync-flush.db'
366
+ const fileId = 1
367
+ const flags = VFS.SQLITE_OPEN_CREATE | VFS.SQLITE_OPEN_READWRITE
368
+ const pOutFlags = new DataView(new ArrayBuffer(4))
369
+
370
+ vfs.jOpen(path, fileId, flags, pOutFlags)
371
+
372
+ // Write data
373
+ const testData = new TextEncoder().encode('Sync test data')
374
+ expect(vfs.jWrite(fileId, testData, 0)).toBe(VFS.SQLITE_OK)
375
+
376
+ // Test different sync modes
377
+ expect(vfs.jSync(fileId, VFS.SQLITE_SYNC_NORMAL)).toBe(VFS.SQLITE_OK)
378
+ expect(vfs.jSync(fileId, VFS.SQLITE_SYNC_FULL)).toBe(VFS.SQLITE_OK)
379
+ expect(vfs.jSync(fileId, VFS.SQLITE_SYNC_DATAONLY)).toBe(VFS.SQLITE_OK)
380
+
381
+ // Verify data is still accessible after sync
382
+ const readData = new Uint8Array(testData.length)
383
+ expect(vfs.jRead(fileId, readData, 0)).toBe(VFS.SQLITE_OK)
384
+ expect(readData).toEqual(testData)
385
+
386
+ expect(vfs.jClose(fileId)).toBe(VFS.SQLITE_OK)
387
+ })
388
+ })
389
+ })