@xnetjs/sqlite 0.0.2 → 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.
- package/dist/{adapter-I7yAV6iu.d.ts → adapter-imtxkmXZ.d.ts} +48 -1
- package/dist/adapters/electron.d.ts +70 -6
- package/dist/adapters/electron.js +662 -36
- package/dist/adapters/expo.d.ts +6 -2
- package/dist/adapters/expo.js +34 -6
- package/dist/adapters/memory.d.ts +6 -2
- package/dist/adapters/memory.js +8 -1
- package/dist/adapters/reader-thread.d.ts +78 -0
- package/dist/adapters/reader-thread.js +57 -0
- package/dist/adapters/web-proxy.d.ts +71 -3
- package/dist/adapters/web-proxy.js +554 -39
- package/dist/adapters/web-router-worker.d.ts +76 -0
- package/dist/adapters/web-router-worker.js +91 -0
- package/dist/adapters/web-worker.d.ts +56 -1
- package/dist/adapters/web-worker.js +253 -14
- package/dist/adapters/web.d.ts +90 -3
- package/dist/adapters/web.js +10 -4
- package/dist/browser-support.d.ts +65 -1
- package/dist/browser-support.js +15 -3
- package/dist/chunk-5HC5V73T.js +191 -0
- package/dist/chunk-BBZDKLA3.js +727 -0
- package/dist/chunk-CBU263LI.js +30 -0
- package/dist/chunk-CGI2YBZY.js +16 -0
- package/dist/chunk-S6MT6KCI.js +279 -0
- package/dist/chunk-SV475UL5.js +44 -0
- package/dist/chunk-W3L4FXU5.js +415 -0
- package/dist/index.d.ts +111 -8
- package/dist/index.js +219 -130
- package/dist/schema-C4gufY3B.d.ts +35 -0
- package/dist/types-BTabr_VP.d.ts +225 -0
- package/dist/worker-scheduler-D04DqMmR.d.ts +56 -0
- package/package.json +5 -1
- package/dist/chunk-BXYZU3OL.js +0 -245
- package/dist/chunk-HIREU5S5.js +0 -193
- package/dist/chunk-ZRR5D2OD.js +0 -140
- package/dist/schema-CjkXTqxn.d.ts +0 -35
- package/dist/types-C_aHfRDF.d.ts +0 -42
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SQLITE_CORRUPT_RESULT_CODE = 11;
|
|
3
|
+
var SQLITE_NOTADB_RESULT_CODE = 26;
|
|
4
|
+
function toErrorLike(error) {
|
|
5
|
+
if (!error || typeof error !== "object") {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
function isSQLiteCorruptionError(error) {
|
|
11
|
+
return isSQLiteCorruptionErrorInternal(error, /* @__PURE__ */ new Set());
|
|
12
|
+
}
|
|
13
|
+
function isSQLiteCorruptionErrorInternal(error, seen) {
|
|
14
|
+
const current = toErrorLike(error);
|
|
15
|
+
if (!current) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (seen.has(error)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
seen.add(error);
|
|
22
|
+
const message = typeof current.message === "string" ? current.message.toLowerCase() : String(current.message);
|
|
23
|
+
const code = typeof current.code === "string" ? current.code.toUpperCase() : "";
|
|
24
|
+
const resultCode = typeof current.resultCode === "number" ? current.resultCode : null;
|
|
25
|
+
return resultCode === SQLITE_CORRUPT_RESULT_CODE || resultCode === SQLITE_NOTADB_RESULT_CODE || code === "SQLITE_CORRUPT" || code === "SQLITE_NOTADB" || message.includes("sqlite_corrupt") || message.includes("sqlite_notadb") || message.includes("database disk image is malformed") || message.includes("file is not a database") || isSQLiteCorruptionErrorInternal(current.cause, seen);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
isSQLiteCorruptionError
|
|
30
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/adapters/boot-log-bridge.ts
|
|
2
|
+
var BOOT_LOG_KEY = "__xnetSqliteBootLog";
|
|
3
|
+
function bootLogMessage(args) {
|
|
4
|
+
return { [BOOT_LOG_KEY]: args };
|
|
5
|
+
}
|
|
6
|
+
function readBootLogArgs(data) {
|
|
7
|
+
if (typeof data === "object" && data !== null && Array.isArray(data[BOOT_LOG_KEY])) {
|
|
8
|
+
return data[BOOT_LOG_KEY];
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
bootLogMessage,
|
|
15
|
+
readBootLogArgs
|
|
16
|
+
};
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// src/browser-support.ts
|
|
2
|
+
function withTimeout(promise, timeoutMs, errorMessage) {
|
|
3
|
+
return Promise.race([
|
|
4
|
+
promise,
|
|
5
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(errorMessage)), timeoutMs))
|
|
6
|
+
]);
|
|
7
|
+
}
|
|
8
|
+
function isSafariPrivateBrowsing() {
|
|
9
|
+
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
10
|
+
if (!isSafari) return false;
|
|
11
|
+
try {
|
|
12
|
+
localStorage.setItem("_test", "1");
|
|
13
|
+
localStorage.removeItem("_test");
|
|
14
|
+
return false;
|
|
15
|
+
} catch {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function checkBrowserSupport() {
|
|
20
|
+
const result = {
|
|
21
|
+
opfs: false,
|
|
22
|
+
worker: true,
|
|
23
|
+
supported: false
|
|
24
|
+
};
|
|
25
|
+
if (typeof Worker === "undefined") {
|
|
26
|
+
result.worker = false;
|
|
27
|
+
result.reason = "Web Workers not supported in this browser.";
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
if (typeof navigator === "undefined" || !navigator.storage?.getDirectory) {
|
|
31
|
+
result.reason = "Origin Private File System (OPFS) not supported. Please use a modern browser (Chrome 102+, Firefox 111+, Safari 16.4+).";
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const testOPFS = async () => {
|
|
36
|
+
await navigator.storage.getDirectory();
|
|
37
|
+
};
|
|
38
|
+
await withTimeout(testOPFS(), 5e3, "OPFS access timeout");
|
|
39
|
+
result.opfs = true;
|
|
40
|
+
result.supported = true;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
43
|
+
const normalized = errorMessage.toLowerCase();
|
|
44
|
+
const safariStorageContextError = normalized.includes("object can not be found here") || normalized.includes("object cannot be found here") || normalized.includes("operation is insecure");
|
|
45
|
+
if (isSafariPrivateBrowsing()) {
|
|
46
|
+
result.warning = "Safari Private Browsing detected. Storage may be limited. For full functionality, switch to normal mode or use the xNet Desktop App.";
|
|
47
|
+
result.supported = true;
|
|
48
|
+
} else if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && safariStorageContextError) {
|
|
49
|
+
result.warning = "Safari storage APIs are restricted in this context. xNet will continue, but persistence may be limited between sessions.";
|
|
50
|
+
result.supported = true;
|
|
51
|
+
} else {
|
|
52
|
+
result.warning = `Storage access limited (${errorMessage}). Data persistence may be limited between sessions. For full functionality, use the xNet Desktop App.`;
|
|
53
|
+
result.supported = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
async function readStorageEstimate() {
|
|
59
|
+
const estimate = await navigator.storage.estimate?.().catch(() => void 0);
|
|
60
|
+
return {
|
|
61
|
+
usageBytes: estimate?.usage,
|
|
62
|
+
quotaBytes: estimate?.quota
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getPersistenceMessage(input) {
|
|
66
|
+
const { persisted, requested, granted } = input;
|
|
67
|
+
if (persisted) {
|
|
68
|
+
return "Durable local storage is enabled. This browser agreed to keep your xNet workspace unless you explicitly clear site data.";
|
|
69
|
+
}
|
|
70
|
+
if (!requested) {
|
|
71
|
+
return "Durable storage is not enabled yet. xNet can request stronger local-storage protection when you choose to enable it.";
|
|
72
|
+
}
|
|
73
|
+
if (granted === false) {
|
|
74
|
+
return "This browser declined durable storage for now. xNet keeps working, and browsers re-evaluate the request as install, notification, and usage signals change.";
|
|
75
|
+
}
|
|
76
|
+
return "This browser did not confirm durable storage. xNet will keep working, but local data may be evicted under storage pressure or aggressive cleanup.";
|
|
77
|
+
}
|
|
78
|
+
async function checkPersistentStorage() {
|
|
79
|
+
return requestPersistentStorage({ request: false });
|
|
80
|
+
}
|
|
81
|
+
function isSilentPersistRequestSafe() {
|
|
82
|
+
if (typeof navigator === "undefined") return false;
|
|
83
|
+
return !/Firefox|FxiOS/i.test(navigator.userAgent);
|
|
84
|
+
}
|
|
85
|
+
function watchPersistentStoragePermission(onChange) {
|
|
86
|
+
let active = true;
|
|
87
|
+
let detach = null;
|
|
88
|
+
void (async () => {
|
|
89
|
+
try {
|
|
90
|
+
const status = await navigator.permissions.query({
|
|
91
|
+
name: "persistent-storage"
|
|
92
|
+
});
|
|
93
|
+
if (!active) return;
|
|
94
|
+
const listener = () => onChange(status.state);
|
|
95
|
+
status.addEventListener("change", listener);
|
|
96
|
+
detach = () => status.removeEventListener("change", listener);
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
})();
|
|
100
|
+
return () => {
|
|
101
|
+
active = false;
|
|
102
|
+
detach?.();
|
|
103
|
+
detach = null;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function requestPersistentStorage(options = { request: true }) {
|
|
107
|
+
const requested = options.request ?? true;
|
|
108
|
+
if (typeof navigator === "undefined" || !navigator.storage) {
|
|
109
|
+
return {
|
|
110
|
+
supported: false,
|
|
111
|
+
persisted: null,
|
|
112
|
+
granted: null,
|
|
113
|
+
requested,
|
|
114
|
+
requestable: false,
|
|
115
|
+
state: "unsupported",
|
|
116
|
+
message: "This browser does not expose storage persistence APIs. Local data can still work, but the browser may evict it under storage pressure."
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const estimate = await readStorageEstimate();
|
|
120
|
+
if (!navigator.storage.persist || !navigator.storage.persisted) {
|
|
121
|
+
return {
|
|
122
|
+
supported: false,
|
|
123
|
+
persisted: null,
|
|
124
|
+
granted: null,
|
|
125
|
+
requested,
|
|
126
|
+
requestable: false,
|
|
127
|
+
state: "unsupported",
|
|
128
|
+
message: "This browser cannot explicitly request durable storage. Local data can still work, but the browser may evict it under storage pressure.",
|
|
129
|
+
...estimate
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const alreadyPersisted = await navigator.storage.persisted();
|
|
134
|
+
const granted = alreadyPersisted ? true : requested ? await navigator.storage.persist() : null;
|
|
135
|
+
const persisted = granted ? true : await navigator.storage.persisted();
|
|
136
|
+
if (persisted) {
|
|
137
|
+
return {
|
|
138
|
+
supported: true,
|
|
139
|
+
persisted,
|
|
140
|
+
granted,
|
|
141
|
+
requested,
|
|
142
|
+
requestable: false,
|
|
143
|
+
state: "granted",
|
|
144
|
+
message: getPersistenceMessage({ persisted, requested, granted }),
|
|
145
|
+
...estimate
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
supported: true,
|
|
150
|
+
persisted,
|
|
151
|
+
granted,
|
|
152
|
+
requested,
|
|
153
|
+
requestable: true,
|
|
154
|
+
state: "not-granted",
|
|
155
|
+
message: getPersistenceMessage({ persisted, requested, granted }),
|
|
156
|
+
...estimate
|
|
157
|
+
};
|
|
158
|
+
} catch (err) {
|
|
159
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
160
|
+
return {
|
|
161
|
+
supported: true,
|
|
162
|
+
persisted: null,
|
|
163
|
+
granted: null,
|
|
164
|
+
requested,
|
|
165
|
+
requestable: true,
|
|
166
|
+
state: "error",
|
|
167
|
+
message: `xNet could not confirm durable storage (${reason}). Local data may still work, but persistence guarantees are unclear.`,
|
|
168
|
+
...estimate
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function showUnsupportedBrowserMessage(reason) {
|
|
173
|
+
const container = document.getElementById("app") ?? document.body;
|
|
174
|
+
container.innerHTML = `
|
|
175
|
+
<div style="
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
align-items: center;
|
|
179
|
+
justify-content: center;
|
|
180
|
+
min-height: 100vh;
|
|
181
|
+
padding: 2rem;
|
|
182
|
+
text-align: center;
|
|
183
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
184
|
+
background: #fafafa;
|
|
185
|
+
color: #333;
|
|
186
|
+
">
|
|
187
|
+
<div style="
|
|
188
|
+
background: white;
|
|
189
|
+
padding: 2rem 2.5rem;
|
|
190
|
+
border-radius: 12px;
|
|
191
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
|
192
|
+
max-width: 480px;
|
|
193
|
+
width: 100%;
|
|
194
|
+
">
|
|
195
|
+
<h1 style="
|
|
196
|
+
font-size: 1.5rem;
|
|
197
|
+
margin: 0 0 1rem 0;
|
|
198
|
+
color: #111;
|
|
199
|
+
font-weight: 600;
|
|
200
|
+
">
|
|
201
|
+
Browser Not Supported
|
|
202
|
+
</h1>
|
|
203
|
+
<p style="
|
|
204
|
+
color: #555;
|
|
205
|
+
margin: 0 0 1.5rem 0;
|
|
206
|
+
line-height: 1.6;
|
|
207
|
+
font-size: 1rem;
|
|
208
|
+
">
|
|
209
|
+
${escapeHtml(reason)}
|
|
210
|
+
</p>
|
|
211
|
+
<div style="
|
|
212
|
+
background: #f5f5f5;
|
|
213
|
+
padding: 1rem;
|
|
214
|
+
border-radius: 8px;
|
|
215
|
+
text-align: left;
|
|
216
|
+
font-size: 0.9rem;
|
|
217
|
+
">
|
|
218
|
+
<p style="margin: 0 0 0.5rem 0; font-weight: 500;">Supported browsers:</p>
|
|
219
|
+
<ul style="margin: 0; padding-left: 1.5rem; color: #666;">
|
|
220
|
+
<li>Chrome 102+ (March 2022)</li>
|
|
221
|
+
<li>Edge 102+ (March 2022)</li>
|
|
222
|
+
<li>Firefox 111+ (March 2023)</li>
|
|
223
|
+
<li>Safari 16.4+ (March 2023)</li>
|
|
224
|
+
</ul>
|
|
225
|
+
</div>
|
|
226
|
+
<p style="
|
|
227
|
+
color: #888;
|
|
228
|
+
font-size: 0.875rem;
|
|
229
|
+
margin: 1.5rem 0 0 0;
|
|
230
|
+
">
|
|
231
|
+
For the best experience, please use the
|
|
232
|
+
<a href="https://xnet.app/download" style="
|
|
233
|
+
color: #0066cc;
|
|
234
|
+
text-decoration: none;
|
|
235
|
+
font-weight: 500;
|
|
236
|
+
">
|
|
237
|
+
xNet Desktop App
|
|
238
|
+
</a>
|
|
239
|
+
or update your browser.
|
|
240
|
+
</p>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
function escapeHtml(text) {
|
|
246
|
+
const div = document.createElement("div");
|
|
247
|
+
div.textContent = text;
|
|
248
|
+
return div.innerHTML;
|
|
249
|
+
}
|
|
250
|
+
var MEMORY_FALLBACK_COUNT_KEY = "xnet:sqlite:memory-fallback-count";
|
|
251
|
+
function recordMemoryFallbackSession() {
|
|
252
|
+
try {
|
|
253
|
+
const count = getMemoryFallbackSessionCount() + 1;
|
|
254
|
+
localStorage.setItem(MEMORY_FALLBACK_COUNT_KEY, String(count));
|
|
255
|
+
return count;
|
|
256
|
+
} catch {
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function getMemoryFallbackSessionCount() {
|
|
261
|
+
try {
|
|
262
|
+
const raw = localStorage.getItem(MEMORY_FALLBACK_COUNT_KEY);
|
|
263
|
+
const parsed = raw === null ? 0 : Number.parseInt(raw, 10);
|
|
264
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
|
|
265
|
+
} catch {
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export {
|
|
271
|
+
checkBrowserSupport,
|
|
272
|
+
checkPersistentStorage,
|
|
273
|
+
isSilentPersistRequestSafe,
|
|
274
|
+
watchPersistentStoragePermission,
|
|
275
|
+
requestPersistentStorage,
|
|
276
|
+
showUnsupportedBrowserMessage,
|
|
277
|
+
recordMemoryFallbackSession,
|
|
278
|
+
getMemoryFallbackSessionCount
|
|
279
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/adapters/opfs-capability.ts
|
|
2
|
+
function resolveScope(scope) {
|
|
3
|
+
if (scope) return scope;
|
|
4
|
+
const g = globalThis;
|
|
5
|
+
return g;
|
|
6
|
+
}
|
|
7
|
+
function supportsOpfs(scope) {
|
|
8
|
+
return typeof resolveScope(scope).navigator?.storage?.getDirectory === "function";
|
|
9
|
+
}
|
|
10
|
+
function supportsSyncAccessHandle(scope) {
|
|
11
|
+
const s = resolveScope(scope);
|
|
12
|
+
if (typeof s.FileSystemSyncAccessHandle !== "undefined") return true;
|
|
13
|
+
const proto = s.FileSystemFileHandle?.prototype;
|
|
14
|
+
return Boolean(proto && "createSyncAccessHandle" in proto);
|
|
15
|
+
}
|
|
16
|
+
function isCrossOriginIsolated(scope) {
|
|
17
|
+
const s = resolveScope(scope);
|
|
18
|
+
return typeof s.SharedArrayBuffer !== "undefined" && s.crossOriginIsolated === true;
|
|
19
|
+
}
|
|
20
|
+
function detectOpfsCapability(scope) {
|
|
21
|
+
const opfs = supportsOpfs(scope);
|
|
22
|
+
const syncAccessHandle = supportsSyncAccessHandle(scope);
|
|
23
|
+
const crossOriginIsolated = isCrossOriginIsolated(scope);
|
|
24
|
+
let mode;
|
|
25
|
+
let reason;
|
|
26
|
+
if (!opfs) {
|
|
27
|
+
mode = "memory";
|
|
28
|
+
reason = "OPFS is unavailable in this context (private browsing or an unsupported engine); local data will not persist across reloads.";
|
|
29
|
+
} else if (syncAccessHandle) {
|
|
30
|
+
mode = "sync-access-handle";
|
|
31
|
+
reason = "OPFS sync access handles available \u2014 using the durable opfs-sahpool fast path.";
|
|
32
|
+
} else {
|
|
33
|
+
mode = "async-opfs";
|
|
34
|
+
reason = "OPFS is available but sync access handles are not (iOS 15.2\u201316.3 or an older WebView); falling back to the slower async OPFS backend. Data still persists.";
|
|
35
|
+
}
|
|
36
|
+
return { opfs, syncAccessHandle, crossOriginIsolated, mode, reason };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
supportsOpfs,
|
|
41
|
+
supportsSyncAccessHandle,
|
|
42
|
+
isCrossOriginIsolated,
|
|
43
|
+
detectOpfsCapability
|
|
44
|
+
};
|