Add app source and tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
alvocool
2026-10-11 10:15:30 +03:00
parent 7e246255c2
commit 38881d1fe1
135 changed files with 21057 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:archive/archive_io.dart';
/// Packs a directory of static files into a gzip-compressed tar archive
/// (contents at the archive root) for a single-shot upload + remote extract.
class WebArchive {
/// Returns the .tar.gz bytes of [dir]'s contents and the number of files.
static (Uint8List, int) tarGz(Directory dir) {
final archive = createArchiveFromDirectory(dir, includeDirName: false);
// CRITICAL: on Windows the entry names use backslashes; a POSIX `tar` on
// the server would then create single files literally named
// `assets\main.js` instead of the `assets/main.js` tree — breaking any
// app with subdirectories (Angular/React assets, etc.). Force forward
// slashes so the archive is valid on Linux.
for (final f in archive.files) {
f.name = f.name.replaceAll('\\', '/');
}
final tar = TarEncoder().encode(archive);
final gz = GZipEncoder().encode(tar);
final count = archive.files.where((f) => f.isFile).length;
// Release the file handles opened while reading the directory so the
// source tree isn't left locked (notably on Windows).
for (final f in archive.files) {
f.closeSync();
}
return (Uint8List.fromList(gz), count);
}
}
/// Top-level entry so packaging can run off the UI isolate via `compute`.
(Uint8List, int) packageWebDir(String path) =>
WebArchive.tarGz(Directory(path));