// 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; }