local-lite 0.0.21 → 0.0.24

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 (50) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +45 -45
  3. package/dist/actions/store.js +15 -15
  4. package/dist/adapters/remote/convex.d.ts +7 -0
  5. package/dist/adapters/remote/convex.js +10 -1
  6. package/dist/adapters/remote/firestore.d.ts +7 -0
  7. package/dist/adapters/remote/firestore.js +23 -1
  8. package/dist/adapters/remote/supabase.d.ts +7 -0
  9. package/dist/adapters/remote/supabase.js +13 -2
  10. package/dist/auth/session.js +27 -27
  11. package/dist/core/client.d.ts +15 -1
  12. package/dist/core/client.js +46 -6
  13. package/dist/core/maintenance.d.ts +3 -1
  14. package/dist/core/maintenance.js +6 -2
  15. package/dist/core/meta-store.js +3 -3
  16. package/dist/core/outbox-store.js +23 -23
  17. package/dist/{react → devtools}/BenchmarkModal.d.ts +1 -1
  18. package/dist/{react → devtools}/BenchmarkModal.js +20 -20
  19. package/dist/{react → devtools}/SyncInspector.d.ts +3 -2
  20. package/dist/{react → devtools}/SyncInspector.js +43 -33
  21. package/dist/devtools/index.d.ts +3 -0
  22. package/dist/devtools/index.js +20 -0
  23. package/dist/keys/store.js +14 -14
  24. package/dist/kv/store.js +13 -13
  25. package/dist/react/index.d.ts +0 -3
  26. package/dist/react/index.js +0 -4
  27. package/dist/scheduler/store.js +28 -28
  28. package/dist/schema/generator.js +28 -28
  29. package/dist/search/store.js +15 -15
  30. package/dist/storage/convex.d.ts +43 -0
  31. package/dist/storage/convex.js +112 -0
  32. package/dist/storage/expo.d.ts +132 -0
  33. package/dist/storage/expo.js +408 -0
  34. package/dist/storage/factory.d.ts +16 -0
  35. package/dist/storage/factory.js +22 -0
  36. package/dist/storage/firebase.d.ts +44 -0
  37. package/dist/storage/firebase.js +135 -0
  38. package/dist/storage/index.d.ts +5 -0
  39. package/dist/storage/index.js +5 -0
  40. package/dist/storage/manager.d.ts +20 -0
  41. package/dist/storage/manager.js +144 -0
  42. package/dist/storage/store.js +24 -24
  43. package/dist/storage/supabase.d.ts +44 -0
  44. package/dist/storage/supabase.js +83 -0
  45. package/dist/storage/types.d.ts +29 -3
  46. package/dist/utils/portability.d.ts +4 -0
  47. package/dist/utils/portability.js +7 -1
  48. package/dist/utils/sql.d.ts +5 -0
  49. package/dist/utils/sql.js +21 -0
  50. package/package.json +204 -195
@@ -96,15 +96,15 @@ class SearchStore {
96
96
  // Snippet column index in FTS5: columns are 0-based: col 0 is row_id, col 1 is columns[0], etc.
97
97
  // We pick column index 1 (or the first indexed text column) for snippet extraction
98
98
  const snippetColIndex = 1;
99
- let sql = `
100
- SELECT
101
- row_id,
102
- rank,
103
- snippet(${ftsTable}, ${snippetColIndex}, '${preTag}', '${postTag}', '...', 15) as snippet_text
104
- FROM ${ftsTable}
105
- WHERE ${ftsTable} MATCH ?
106
- ORDER BY rank
107
- LIMIT ? OFFSET ?;
99
+ let sql = `
100
+ SELECT
101
+ row_id,
102
+ rank,
103
+ snippet(${ftsTable}, ${snippetColIndex}, '${preTag}', '${postTag}', '...', 15) as snippet_text
104
+ FROM ${ftsTable}
105
+ WHERE ${ftsTable} MATCH ?
106
+ ORDER BY rank
107
+ LIMIT ? OFFSET ?;
108
108
  `;
109
109
  try {
110
110
  const rows = await db.execute(sql, [matchQuery, limit, offset]);
@@ -117,12 +117,12 @@ class SearchStore {
117
117
  catch (err) {
118
118
  // In case snippet() function is unavailable in the environment, fallback to rank-only search
119
119
  if (err?.message?.includes('snippet') || err?.message?.includes('no such function')) {
120
- const fallbackSql = `
121
- SELECT row_id, rank
122
- FROM ${ftsTable}
123
- WHERE ${ftsTable} MATCH ?
124
- ORDER BY rank
125
- LIMIT ? OFFSET ?;
120
+ const fallbackSql = `
121
+ SELECT row_id, rank
122
+ FROM ${ftsTable}
123
+ WHERE ${ftsTable} MATCH ?
124
+ ORDER BY rank
125
+ LIMIT ? OFFSET ?;
126
126
  `;
127
127
  const rows = await db.execute(fallbackSql, [matchQuery, limit, offset]);
128
128
  return (rows || []).map((r) => ({
@@ -0,0 +1,43 @@
1
+ import { BlobRecord, RemoteStorageUploader } from './types.js';
2
+ export interface ConvexStorageUploaderOptions {
3
+ /**
4
+ * Name or function reference for Convex mutation that generates an upload URL.
5
+ * Default: 'sync:generateUploadUrl' (or can be `api.files.generateUploadUrl`)
6
+ */
7
+ uploadMutation?: any;
8
+ /**
9
+ * Optional arguments passed to uploadMutation.
10
+ */
11
+ uploadMutationArgs?: Record<string, any> | ((blob: BlobRecord) => Record<string, any>);
12
+ /**
13
+ * Optional name or function reference for Convex query that gets a serving URL from a storageId.
14
+ * e.g. `api.files.getUrl`
15
+ */
16
+ getUrlQuery?: any;
17
+ /**
18
+ * Optional name or function reference for Convex mutation called after file is uploaded,
19
+ * allowing you to persist metadata or link the storageId to your Convex schema.
20
+ */
21
+ saveFileMutation?: any;
22
+ /**
23
+ * Optional name or function reference for Convex mutation called when a file is deleted.
24
+ */
25
+ deleteMutation?: any;
26
+ /**
27
+ * Custom path / metadata transformation.
28
+ */
29
+ pathTransform?: (key: string, blob?: BlobRecord) => string;
30
+ /**
31
+ * Custom fetch function (defaults to global fetch).
32
+ */
33
+ fetchFn?: typeof fetch;
34
+ }
35
+ export interface ConvexStorageUploaderInstance extends RemoteStorageUploader {
36
+ getUrl(storageId: string): Promise<string | null>;
37
+ getDownloadUrl(keyOrStorageId: string): Promise<string>;
38
+ delete(storageIdOrKey: string): Promise<void>;
39
+ }
40
+ /**
41
+ * Creates a RemoteStorageUploader that syncs binary files to Convex File Storage.
42
+ */
43
+ export declare function createConvexStorageUploader(convex: any, options?: ConvexStorageUploaderOptions): ConvexStorageUploaderInstance;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createConvexStorageUploader = createConvexStorageUploader;
4
+ /**
5
+ * Creates a RemoteStorageUploader that syncs binary files to Convex File Storage.
6
+ */
7
+ function createConvexStorageUploader(convex, options = {}) {
8
+ const uploadMutation = options.uploadMutation ?? 'sync:generateUploadUrl';
9
+ const fetchFn = options.fetchFn ?? (typeof fetch !== 'undefined' ? fetch : undefined);
10
+ if (!convex) {
11
+ throw new Error('Convex client must be provided to createConvexStorageUploader.');
12
+ }
13
+ // Cache of key/storageId mapping
14
+ const storageIdMap = new Map();
15
+ return {
16
+ async upload(blob, data) {
17
+ if (!fetchFn) {
18
+ throw new Error('Fetch API is not available in the current environment.');
19
+ }
20
+ // 1. Generate upload URL via mutation
21
+ const mutationArgs = typeof options.uploadMutationArgs === 'function'
22
+ ? options.uploadMutationArgs(blob)
23
+ : options.uploadMutationArgs || {};
24
+ let postUrl;
25
+ if (typeof convex.mutation === 'function') {
26
+ postUrl = await convex.mutation(uploadMutation, mutationArgs);
27
+ }
28
+ else if (typeof convex === 'function') {
29
+ postUrl = await convex(uploadMutation, mutationArgs);
30
+ }
31
+ else {
32
+ throw new Error('Convex client must support .mutation() method.');
33
+ }
34
+ if (!postUrl || typeof postUrl !== 'string') {
35
+ throw new Error(`Convex generateUploadUrl mutation did not return a valid URL: ${JSON.stringify(postUrl)}`);
36
+ }
37
+ // 2. POST binary data to upload URL
38
+ const response = await fetchFn(postUrl, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': blob.mimeType || 'application/octet-stream',
42
+ },
43
+ body: data,
44
+ });
45
+ if (!response.ok) {
46
+ throw new Error(`Convex file upload failed with status ${response.status}: ${response.statusText}`);
47
+ }
48
+ const jsonResult = await response.json();
49
+ const storageId = jsonResult?.storageId || jsonResult?.id || jsonResult;
50
+ if (!storageId) {
51
+ throw new Error('Convex upload response did not contain a valid storageId.');
52
+ }
53
+ storageIdMap.set(blob.key, storageId);
54
+ // 3. Optional: save file record in Convex schema
55
+ if (options.saveFileMutation) {
56
+ const filePayload = {
57
+ storageId,
58
+ key: blob.key,
59
+ name: blob.name,
60
+ mimeType: blob.mimeType,
61
+ size: blob.size,
62
+ sha256: blob.sha256,
63
+ metadata: blob.metadata,
64
+ };
65
+ if (typeof convex.mutation === 'function') {
66
+ await convex.mutation(options.saveFileMutation, filePayload);
67
+ }
68
+ }
69
+ // 4. Resolve serving URL if query is provided
70
+ let remoteUrl = storageId;
71
+ if (options.getUrlQuery) {
72
+ const resolved = await this.getUrl(storageId);
73
+ if (resolved) {
74
+ remoteUrl = resolved;
75
+ }
76
+ }
77
+ return {
78
+ remoteUrl,
79
+ storageId,
80
+ metadata: { storageId },
81
+ };
82
+ },
83
+ async getUrl(storageId) {
84
+ if (!options.getUrlQuery) {
85
+ return null;
86
+ }
87
+ try {
88
+ if (typeof convex.query === 'function') {
89
+ return await convex.query(options.getUrlQuery, { storageId });
90
+ }
91
+ return null;
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ },
97
+ async getDownloadUrl(keyOrStorageId) {
98
+ const storageId = storageIdMap.get(keyOrStorageId) || keyOrStorageId;
99
+ const url = await this.getUrl(storageId);
100
+ return url || storageId;
101
+ },
102
+ async delete(storageIdOrKey) {
103
+ const storageId = storageIdMap.get(storageIdOrKey) || storageIdOrKey;
104
+ storageIdMap.delete(storageIdOrKey);
105
+ if (options.deleteMutation) {
106
+ if (typeof convex.mutation === 'function') {
107
+ await convex.mutation(options.deleteMutation, { storageId });
108
+ }
109
+ }
110
+ },
111
+ };
112
+ }
@@ -0,0 +1,132 @@
1
+ import { FileDriver } from './types.js';
2
+ export interface ExpoFileSystemModule {
3
+ File?: any;
4
+ Directory?: any;
5
+ Paths?: any;
6
+ documentDirectory?: string | null;
7
+ cacheDirectory?: string | null;
8
+ EncodingType?: {
9
+ UTF8: string;
10
+ Base64: string;
11
+ };
12
+ getInfoAsync?(fileUri: string, options?: {
13
+ md5?: boolean;
14
+ size?: boolean;
15
+ }): Promise<{
16
+ exists: boolean;
17
+ isDirectory?: boolean;
18
+ size?: number;
19
+ uri?: string;
20
+ }>;
21
+ writeAsStringAsync?(fileUri: string, contents: string, options?: {
22
+ encoding?: string;
23
+ }): Promise<void>;
24
+ readAsStringAsync?(fileUri: string, options?: {
25
+ encoding?: string;
26
+ length?: number;
27
+ position?: number;
28
+ }): Promise<string>;
29
+ makeDirectoryAsync?(fileUri: string, options?: {
30
+ intermediates?: boolean;
31
+ }): Promise<void>;
32
+ deleteAsync?(fileUri: string, options?: {
33
+ idempotent?: boolean;
34
+ }): Promise<void>;
35
+ copyAsync?(options: {
36
+ from: string;
37
+ to: string;
38
+ }): Promise<void>;
39
+ moveAsync?(options: {
40
+ from: string;
41
+ to: string;
42
+ }): Promise<void>;
43
+ downloadAsync?(url: string, fileUri: string, options?: {
44
+ md5?: boolean;
45
+ headers?: Record<string, string>;
46
+ sessionType?: any;
47
+ }): Promise<{
48
+ uri: string;
49
+ status: number;
50
+ headers: Record<string, string>;
51
+ md5?: string;
52
+ }>;
53
+ }
54
+ export interface ExpoFileDriverOptions {
55
+ /**
56
+ * The modern `File` class from `expo-file-system` (SDK >57/58).
57
+ * e.g. `import { File } from 'expo-file-system'`
58
+ */
59
+ File?: any;
60
+ /**
61
+ * The modern `Directory` class from `expo-file-system`.
62
+ * e.g. `import { Directory } from 'expo-file-system'`
63
+ */
64
+ Directory?: any;
65
+ /**
66
+ * The modern `Paths` object from `expo-file-system`.
67
+ * e.g. `import { Paths } from 'expo-file-system'`
68
+ */
69
+ Paths?: any;
70
+ /**
71
+ * The `expo-file-system` module instance.
72
+ * e.g. `import * as FileSystem from 'expo-file-system'`
73
+ */
74
+ fileSystem?: ExpoFileSystemModule | any;
75
+ /**
76
+ * Base directory path or `Directory` instance for storing files.
77
+ * Defaults to: `new Directory(Paths.document, 'local-lite-blobs')`
78
+ */
79
+ baseDir?: any;
80
+ /**
81
+ * Whether to store files in `Paths.cache` instead of `Paths.document`.
82
+ * Files in cache directory may be cleared by the OS if device storage runs low.
83
+ * Default: false
84
+ */
85
+ useCache?: boolean;
86
+ }
87
+ /**
88
+ * Universal binary <-> base64 utilities compatible with Node, Browser, and React Native (Hermes).
89
+ */
90
+ export declare function bytesToBase64(bytes: Uint8Array): string;
91
+ export declare function base64ToBytes(base64: string): Uint8Array;
92
+ /**
93
+ * FileDriver implementation for Expo / React Native environments.
94
+ * Uses modern Expo (>57/58) `File`, `Directory`, and `Paths` APIs when available,
95
+ * with seamless fallback for legacy `expo-file-system` environments.
96
+ */
97
+ export declare class ExpoFileDriver implements FileDriver {
98
+ private FileClass?;
99
+ private DirectoryClass?;
100
+ private PathsObj?;
101
+ private legacyFs?;
102
+ private baseDirOption?;
103
+ private useCache;
104
+ private resolvedBaseDir;
105
+ private resolvedBaseDirPath;
106
+ private ensuredDirs;
107
+ constructor(options?: ExpoFileDriverOptions);
108
+ private resolveClasses;
109
+ private getBaseDirectory;
110
+ /**
111
+ * Resolves a key to a modern Expo `File` instance (if File class is available)
112
+ * or a string URI path.
113
+ */
114
+ private resolveFileOrUri;
115
+ resolveUri(key: string): Promise<string>;
116
+ getUri(key: string): Promise<string>;
117
+ private ensureDirectory;
118
+ write(key: string, data: Uint8Array): Promise<string>;
119
+ read(key: string): Promise<Uint8Array | null>;
120
+ delete(key: string): Promise<void>;
121
+ exists(key: string): Promise<boolean>;
122
+ getSize(key: string): Promise<number>;
123
+ /**
124
+ * Fast file copy from an existing local URI (e.g. from expo-image-picker or expo-document-picker)
125
+ * into local-lite managed storage without reading entire file contents into memory.
126
+ */
127
+ copyFrom(sourceUri: string, key: string): Promise<string>;
128
+ /**
129
+ * Downloads a remote URL directly to the destination key on disk.
130
+ */
131
+ downloadFrom(remoteUrl: string, key: string): Promise<string>;
132
+ }