Something went wrong. Try again.
Content-addressed version deploy system for Diffuse elements.diffuse.sh
Something went wrong. Try again.
2.6 kB · 86 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687import { importer } from "ipfs-unixfs-importer";import type { FileCandidate } from "ipfs-unixfs-importer";import { fixedSize } from "ipfs-unixfs-importer/chunker";import { balanced } from "ipfs-unixfs-importer/layout";import { CarWriter } from "@ipld/car";import { CID } from "multiformats/cid";import { walk } from "@std/fs";import { join, relative } from "@std/path";
/** * Create a CAR file of a directory. */export async function createCAR( dirPath: string, carPath: string,): Promise<string> { const blockstore = new Map<string, Uint8Array>();
const options = { cidVersion: 1 as const, rawLeaves: true, chunker: fixedSize({ chunkSize: 1048576 }), layout: balanced({ maxChildrenPerNode: 1024 }), hashAlg: "sha2-256", };
let rootCid: CID | undefined;
for await ( const entry of importer(walkDir(dirPath), { put: async (cid: CID, block: Uint8Array): Promise<CID> => { blockstore.set(cid.toString(), block); return cid; }, }, options) ) { rootCid = entry.cid; }
if (rootCid === undefined) throw new Error("importer produced no root CID");
const { writer, out } = CarWriter.create([rootCid]);
const file = await Deno.open(carPath, { write: true, create: true, truncate: true, }); const writePromise = ReadableStream.from(out).pipeTo(file.writable);
for (const [cidStr, block] of blockstore) { await writer.put({ cid: CID.parse(cidStr), bytes: block }); }
await writer.close(); await writePromise;
return rootCid.toString();}
// 🛠️
async function* walkDir(dirPath: string): AsyncGenerator<FileCandidate> { // Collect and sort paths so the resulting CID is deterministic regardless // of filesystem entry order (which changes when a directory is copied). const paths: string[] = []; for await ( const entry of walk(dirPath, { includeFiles: true, includeDirs: false }) ) { paths.push(relative(dirPath, entry.path)); } paths.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
// Prefix all paths with a common root directory so the importer builds a // wrapping root directory node. Without this, the importer only yields // subdirectory nodes (e.g. "vendor") and never a root directory, so the // last entry's CID would be a subdirectory rather than the true root. // The prefix name doesn't affect any CIDs — only the directory structure // matters, and the root's link names come from the last path component. for (const path of paths) { yield { path: "root/" + path, content: await Deno.readFile(join(dirPath, path)), }; }}