@livestore/sqlite-wasm 0.3.1 → 0.3.2-dev.1

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.
@@ -2,12 +2,12 @@ import type { MakeSqliteDb, PersistenceInfo, SqliteDb } from '@livestore/common'
2
2
  import { Effect, Hash } from '@livestore/utils/effect'
3
3
  import type { MemoryVFS } from '@livestore/wa-sqlite/src/examples/MemoryVFS.js'
4
4
 
5
- import { makeInMemoryDb } from '../in-memory-vfs.js'
6
- import { makeSqliteDb } from '../make-sqlite-db.js'
7
- import type { AccessHandlePoolVFS } from './opfs/AccessHandlePoolVFS.js'
8
- import { makeOpfsDb } from './opfs/index.js'
5
+ import { makeInMemoryDb } from '../in-memory-vfs.ts'
6
+ import { makeSqliteDb } from '../make-sqlite-db.ts'
7
+ import type { AccessHandlePoolVFS } from './opfs/AccessHandlePoolVFS.ts'
8
+ import { makeOpfsDb } from './opfs/index.ts'
9
9
 
10
- export * from './opfs/opfs-sah-pool.js'
10
+ export * from './opfs/opfs-sah-pool.ts'
11
11
 
12
12
  export type WebDatabaseMetadataInMemory = {
13
13
  _tag: 'in-memory'
@@ -1,9 +1,7 @@
1
- /* eslint-disable prefer-arrow/prefer-arrow-functions */
2
-
1
+ import { Effect, Schedule, Schema } from '@livestore/utils/effect'
3
2
  // Based on https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/AccessHandlePoolVFS.js
4
3
  import * as VFS from '@livestore/wa-sqlite/src/VFS.js'
5
-
6
- import { FacadeVFS } from '../../FacadeVFS.js'
4
+ import { FacadeVFS } from '../../FacadeVFS.ts'
7
5
 
8
6
  const SECTOR_SIZE = 4096
9
7
 
@@ -123,7 +121,9 @@ export class AccessHandlePoolVFS extends FacadeVFS {
123
121
 
124
122
  jRead(fileId: number, pData: Uint8Array, iOffset: number): number {
125
123
  const file = this.#mapIdToFile.get(fileId)!
126
- const nBytes = file.accessHandle.read(pData.subarray(), { at: HEADER_OFFSET_DATA + iOffset })
124
+ const nBytes = file.accessHandle.read(pData.subarray(), {
125
+ at: HEADER_OFFSET_DATA + iOffset,
126
+ })
127
127
  if (nBytes < pData.byteLength) {
128
128
  pData.fill(0, nBytes, pData.byteLength)
129
129
  return VFS.SQLITE_IOERR_SHORT_READ
@@ -133,7 +133,9 @@ export class AccessHandlePoolVFS extends FacadeVFS {
133
133
 
134
134
  jWrite(fileId: number, pData: Uint8Array, iOffset: number): number {
135
135
  const file = this.#mapIdToFile.get(fileId)!
136
- const nBytes = file.accessHandle.write(pData.subarray(), { at: HEADER_OFFSET_DATA + iOffset })
136
+ const nBytes = file.accessHandle.write(pData.subarray(), {
137
+ at: HEADER_OFFSET_DATA + iOffset,
138
+ })
137
139
  return nBytes === pData.byteLength ? VFS.SQLITE_OK : VFS.SQLITE_IOERR
138
140
  }
139
141
 
@@ -164,7 +166,7 @@ export class AccessHandlePoolVFS extends FacadeVFS {
164
166
  return VFS.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
165
167
  }
166
168
 
167
- jAccess(zName: string, flags: number, pResOut: DataView): number {
169
+ jAccess(zName: string, _flags: number, pResOut: DataView): number {
168
170
  const path = this.#getPath(zName)
169
171
  pResOut.setInt32(0, this.#mapPathToAccessHandle.has(path) ? 1 : 0, true)
170
172
  return VFS.SQLITE_OK
@@ -219,8 +221,14 @@ export class AccessHandlePoolVFS extends FacadeVFS {
219
221
  async addCapacity(n: number): Promise<number> {
220
222
  for (let i = 0; i < n; ++i) {
221
223
  const name = Math.random().toString(36).replace('0.', '')
222
- const handle = await this.#directoryHandle!.getFileHandle(name, { create: true })
223
- const accessHandle = await handle.createSyncAccessHandle()
224
+ const handle = await this.#directoryHandle!.getFileHandle(name, {
225
+ create: true,
226
+ })
227
+
228
+ const accessHandle = await Effect.tryPromise({
229
+ try: () => handle.createSyncAccessHandle(),
230
+ catch: (cause) => new OpfsError({ cause, path: name }),
231
+ }).pipe(Effect.retry(Schedule.exponentialBackoff10Sec), Effect.runPromise)
224
232
  this.#mapAccessHandleToName.set(accessHandle, name)
225
233
 
226
234
  this.#setAssociatedPath(accessHandle, '', 0)
@@ -236,7 +244,7 @@ export class AccessHandlePoolVFS extends FacadeVFS {
236
244
  async removeCapacity(n: number): Promise<number> {
237
245
  let nRemoved = 0
238
246
  for (const accessHandle of Array.from(this.#availableAccessHandles)) {
239
- if (nRemoved == n || this.getSize() === this.getCapacity()) return nRemoved
247
+ if (nRemoved === n || this.getSize() === this.getCapacity()) return nRemoved
240
248
 
241
249
  const name = this.#mapAccessHandleToName.get(accessHandle)!
242
250
  accessHandle.close()
@@ -260,7 +268,10 @@ export class AccessHandlePoolVFS extends FacadeVFS {
260
268
  // Open access handles in parallel, separating associated and unassociated.
261
269
  await Promise.all(
262
270
  files.map(async ([name, handle]) => {
263
- const accessHandle = await handle.createSyncAccessHandle()
271
+ const accessHandle = await Effect.tryPromise({
272
+ try: () => handle.createSyncAccessHandle(),
273
+ catch: (cause) => new OpfsError({ cause, path: name }),
274
+ }).pipe(Effect.retry(Schedule.exponentialBackoff10Sec), Effect.runPromise)
264
275
  this.#mapAccessHandleToName.set(accessHandle, name)
265
276
  const path = this.#getAssociatedPath(accessHandle)
266
277
  if (path) {
@@ -402,3 +413,8 @@ export class AccessHandlePoolVFS extends FacadeVFS {
402
413
  }
403
414
  }
404
415
  }
416
+
417
+ export class OpfsError extends Schema.TaggedError<OpfsError>()('OpfsError', {
418
+ cause: Schema.Defect,
419
+ path: Schema.String,
420
+ }) {}
@@ -1,7 +1,7 @@
1
1
  import { Effect } from '@livestore/utils/effect'
2
2
  import type * as WaSqlite from '@livestore/wa-sqlite'
3
3
 
4
- import { AccessHandlePoolVFS } from './AccessHandlePoolVFS.js'
4
+ import { AccessHandlePoolVFS } from './AccessHandlePoolVFS.ts'
5
5
 
6
6
  const semaphore = Effect.makeSemaphore(1).pipe(Effect.runSync)
7
7
  const opfsVfsMap = new Map<string, AccessHandlePoolVFS>()
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * as WaSqlite from './index_.js'
1
+ export * as WaSqlite from './index_.ts'
package/src/index_.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from '@livestore/wa-sqlite'
2
- export * from './make-sqlite-db.js'
2
+ export * from './make-sqlite-db.ts'
@@ -6,9 +6,9 @@ import type {
6
6
  SqliteDbChangeset,
7
7
  } from '@livestore/common'
8
8
  import { SqliteDbHelper, SqliteError } from '@livestore/common'
9
+ import { EventSequenceNumber } from '@livestore/common/schema'
9
10
  import * as SqliteConstants from '@livestore/wa-sqlite/src/sqlite-constants.js'
10
-
11
- import { makeInMemoryDb } from './in-memory-vfs.js'
11
+ import { makeInMemoryDb } from './in-memory-vfs.ts'
12
12
 
13
13
  export const makeSqliteDb = <
14
14
  TMetadata extends {
@@ -32,6 +32,10 @@ export const makeSqliteDb = <
32
32
  const sqliteDb: SqliteDb<TMetadata> = {
33
33
  _tag: 'SqliteDb',
34
34
  metadata,
35
+ debug: {
36
+ // Setting initially to root but will be set to correct value shortly after
37
+ head: EventSequenceNumber.ROOT,
38
+ },
35
39
  prepare: (queryStr) => {
36
40
  try {
37
41
  const stmts = sqlite3.statements(dbPointer, queryStr.trim(), { unscoped: true })
@@ -75,10 +79,9 @@ export const makeSqliteDb = <
75
79
 
76
80
  try {
77
81
  // NOTE `column_names` only works for `SELECT` statements, ignoring other statements for now
78
- let columns = undefined
82
+ let columns: string[] | undefined
79
83
  try {
80
84
  columns = sqlite3.column_names(stmt)
81
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
85
  } catch (_e) {}
83
86
 
84
87
  while (sqlite3.step(stmt) === SqliteConstants.SQLITE_ROW) {
@@ -209,7 +212,7 @@ export const makeSqliteDb = <
209
212
  try {
210
213
  sqlite3.changeset_apply(dbPointer, data)
211
214
  // @ts-expect-error data should be garbage collected after use
212
- // biome-ignore lint/style/noParameterAssign:
215
+ // biome-ignore lint/style/noParameterAssign: ...
213
216
  data = undefined
214
217
  } catch (cause: any) {
215
218
  throw new SqliteError({
@@ -1,13 +1,12 @@
1
1
  /// <reference types="node" />
2
2
 
3
- /* eslint-disable prefer-arrow/prefer-arrow-functions */
4
3
  import * as fs from 'node:fs'
5
4
  import path from 'node:path'
6
5
 
7
6
  import type * as WaSqlite from '@livestore/wa-sqlite'
8
7
  import * as VFS from '@livestore/wa-sqlite/src/VFS.js'
9
8
 
10
- import { FacadeVFS } from '../FacadeVFS.js'
9
+ import { FacadeVFS } from '../FacadeVFS.ts'
11
10
 
12
11
  interface NodeFsFile {
13
12
  pathname: string
package/src/node/mod.ts CHANGED
@@ -5,9 +5,9 @@ import { Effect, FileSystem } from '@livestore/utils/effect'
5
5
  import type * as WaSqlite from '@livestore/wa-sqlite'
6
6
  import type { MemoryVFS } from '@livestore/wa-sqlite/src/examples/MemoryVFS.js'
7
7
 
8
- import { makeInMemoryDb } from '../in-memory-vfs.js'
9
- import { makeSqliteDb } from '../make-sqlite-db.js'
10
- import { NodeFS } from './NodeFS.js'
8
+ import { makeInMemoryDb } from '../in-memory-vfs.ts'
9
+ import { makeSqliteDb } from '../make-sqlite-db.ts'
10
+ import { NodeFS } from './NodeFS.ts'
11
11
 
12
12
  export type NodeDatabaseMetadataInMemory = {
13
13
  _tag: 'in-memory'