// Pack an unpacked tile — a directory with manifest.json + index.html and
// whatever else it ships — into a .tile file, using ziran's own writer.
// The ONE dir→tile assembly: build:tiles and `ziran publish
` both
// run this. (Lives under cli/, not tilefile.ts: it walks the real
// filesystem with Deno APIs, which the browser bundles must never see.)
import { basename, join } from 'jsr:@std/path@1';
import mime from 'mime';
import { type Masl, writeTile } from '../server/tilefile.ts';
async function* walkFiles(root: string, prefix = ''): AsyncGenerator {
for await (const entry of Deno.readDir(join(root, prefix))) {
const rel = `${prefix}/${entry.name}`;
if (entry.isDirectory) yield* walkFiles(root, rel);
else if (entry.isFile) yield rel;
}
}
/** Assemble the tile rooted at `dir` into `out`. Returns the manifest. */
export async function packTileDir(dir: string, out: string): Promise {
const manifest = JSON.parse(await Deno.readTextFile(join(dir, 'manifest.json'))) as Masl;
manifest.resources ??= {};
const resources = new Map();
for await (const file of walkFiles(dir)) {
if (file === '/manifest.json' || basename(file) === '.DS_Store') continue;
const res = file === '/index.html' ? '/' : file;
resources.set(res, await Deno.readFile(join(dir, file)));
manifest.resources[res] = {
...(manifest.resources[res] ?? {}),
'content-type': mime.getType(file) ?? 'application/octet-stream',
};
}
if (!resources.has('/')) throw new Error(`${dir} has no index.html`);
await writeTile(manifest, resources, out);
return manifest;
}