@massif-maps/web 6.1.2 → 6.2.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/index.d.ts +6 -0
- package/index.mjs +3 -1
- package/massif-maps.bundle.mjs +78 -6
- package/massif-web-full.mjs +1 -1
- package/massif-web-full.wasm +0 -0
- package/massif-web.mjs +1 -1
- package/massif-web.wasm +0 -0
- package/massif.mjs +77 -0
- package/package.json +2 -2
package/massif-web.wasm
CHANGED
|
Binary file
|
package/massif.mjs
CHANGED
|
@@ -389,3 +389,80 @@ export async function loadModule({ variant, moduleUrl = new URL(`${MODULE_NAME}$
|
|
|
389
389
|
export async function loadMassif(options = {}) {
|
|
390
390
|
return new Massif(await loadModule(options));
|
|
391
391
|
}
|
|
392
|
+
|
|
393
|
+
const S_IFMT = 0o170000;
|
|
394
|
+
const S_IFDIR = 0o040000;
|
|
395
|
+
// WASMFS stats in whole seconds; the legacy FS gave a Date.
|
|
396
|
+
const statSeconds = (time) => (typeof time === 'number' ? time : Math.floor(time.getTime() / 1000));
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Keeps `path` of the module's filesystem in OPFS: restored now, written back every `interval` ms and on pagehide.
|
|
400
|
+
* The files stay in wasm memory, so a tile cache never waits on storage. Resolves to flush().
|
|
401
|
+
*/
|
|
402
|
+
export async function persistDirectory(module, path, { interval = 10000 } = {}) {
|
|
403
|
+
const { FS } = module;
|
|
404
|
+
FS.mkdirTree(path);
|
|
405
|
+
let root = await navigator.storage.getDirectory();
|
|
406
|
+
for (const name of path.split('/').filter(Boolean)) {
|
|
407
|
+
root = await root.getDirectoryHandle(name, { create: true });
|
|
408
|
+
}
|
|
409
|
+
// Per file, the mtime OPFS holds and the second it was copied: an mtime in that second may postdate the copy.
|
|
410
|
+
const written = new Map();
|
|
411
|
+
const unchanged = (child, mtime) => {
|
|
412
|
+
const entry = written.get(child);
|
|
413
|
+
return entry !== undefined && entry.mtime === mtime && mtime < entry.at;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
async function restore(handle, dir) {
|
|
417
|
+
for await (const [name, entry] of handle.entries()) {
|
|
418
|
+
const child = `${dir}/${name}`;
|
|
419
|
+
if (entry.kind === 'directory') {
|
|
420
|
+
FS.mkdirTree(child);
|
|
421
|
+
await restore(entry, child);
|
|
422
|
+
} else {
|
|
423
|
+
FS.writeFile(child, new Uint8Array(await (await entry.getFile()).arrayBuffer()));
|
|
424
|
+
written.set(child, { mtime: statSeconds(FS.stat(child).mtime), at: Infinity });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function save(handle, dir) {
|
|
430
|
+
const names = new Set(FS.readdir(dir).filter((name) => name !== '.' && name !== '..'));
|
|
431
|
+
// A stale sqlite journal restored beside a newer database rolls it back. Only what this page knew, not another tab's.
|
|
432
|
+
for (const child of [...written.keys()]) {
|
|
433
|
+
const name = child.slice(dir.length + 1);
|
|
434
|
+
if (child.startsWith(`${dir}/`) && !name.includes('/') && !names.has(name)) {
|
|
435
|
+
await handle.removeEntry(name).catch(() => {});
|
|
436
|
+
written.delete(child);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
for (const name of names) {
|
|
440
|
+
const child = `${dir}/${name}`;
|
|
441
|
+
const stat = FS.stat(child);
|
|
442
|
+
if ((stat.mode & S_IFMT) === S_IFDIR) {
|
|
443
|
+
await save(await handle.getDirectoryHandle(name, { create: true }), child);
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
const mtime = statSeconds(stat.mtime);
|
|
447
|
+
if (unchanged(child, mtime)) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const at = Math.floor(Date.now() / 1000);
|
|
451
|
+
const data = FS.readFile(child);
|
|
452
|
+
const writable = await (await handle.getFileHandle(name, { create: true })).createWritable();
|
|
453
|
+
await writable.write(data);
|
|
454
|
+
await writable.close();
|
|
455
|
+
written.set(child, { mtime, at });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
await restore(root, path.replace(/\/+$/, ''));
|
|
460
|
+
let saving = null;
|
|
461
|
+
const flush = () => {
|
|
462
|
+
saving ??= save(root, path.replace(/\/+$/, '')).finally(() => { saving = null; });
|
|
463
|
+
return saving;
|
|
464
|
+
};
|
|
465
|
+
setInterval(flush, interval);
|
|
466
|
+
addEventListener('pagehide', flush);
|
|
467
|
+
return flush;
|
|
468
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massif-maps/web",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
4
4
|
"description": "Massif Maps in the browser: the SDK compiled to WebAssembly, with its typed API",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"type": "module",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@massif-maps/api": "6.
|
|
29
|
+
"@massif-maps/api": "6.2.0"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|