or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddata-io.mdfilesystem.mdindex.mdreading.mdstreaming.mdwriting.md

filesystem.mddocs/

0

# Filesystem API

1

2

High-level filesystem-like operations for complex ZIP manipulation, providing an intuitive interface for managing ZIP archives as virtual filesystems.

3

4

## fs Object

5

6

The main entry point for the filesystem API.

7

8

```typescript { .api }

9

const fs: {

10

FS: typeof FS;

11

ZipDirectoryEntry: typeof ZipDirectoryEntry;

12

ZipFileEntry: typeof ZipFileEntry;

13

};

14

```

15

16

### Usage

17

18

```javascript

19

import { fs } from "@zip.js/zip.js";

20

21

// Create a new filesystem

22

const zipFs = new fs.FS();

23

24

// Add files and directories

25

zipFs.addText("readme.txt", "Welcome!");

26

const assetsDir = zipFs.addDirectory("assets");

27

assetsDir.addBlob("logo.png", logoBlob);

28

29

// Export as ZIP

30

const zipBlob = await zipFs.exportBlob();

31

```

32

33

## FS Class

34

35

The root filesystem class that manages ZIP entries as a virtual filesystem.

36

37

```typescript { .api }

38

class FS extends ZipDirectoryEntry {

39

readonly root: ZipDirectoryEntry;

40

41

remove(entry: ZipEntry): void;

42

move(entry: ZipEntry, destination: ZipDirectoryEntry): void;

43

find(fullname: string): ZipEntry | undefined;

44

getById(id: number): ZipEntry | undefined;

45

}

46

```

47

48

### Properties

49

50

- **`root`**: The root directory entry

51

52

### Methods

53

54

#### remove()

55

56

Removes an entry and all its children from the filesystem.

57

58

```javascript

59

const fileEntry = zipFs.addText("temp.txt", "temporary");

60

zipFs.remove(fileEntry); // File is removed from filesystem

61

```

62

63

#### move()

64

65

Moves an entry to a different directory.

66

67

```javascript

68

const file = zipFs.addText("misplaced.txt", "content");

69

const targetDir = zipFs.addDirectory("correct-location");

70

zipFs.move(file, targetDir); // Now at "correct-location/misplaced.txt"

71

```

72

73

#### find()

74

75

Finds an entry by its full path.

76

77

```javascript

78

const entry = zipFs.find("assets/images/logo.png");

79

if (entry && !entry.directory) {

80

const blob = await entry.getBlob();

81

}

82

```

83

84

#### getById()

85

86

Finds an entry by its unique ID.

87

88

```javascript

89

const entry = zipFs.getById(123);

90

if (entry) {

91

console.log(`Found: ${entry.getFullname()}`);

92

}

93

```

94

95

## ZipEntry Base Class

96

97

Base class for all filesystem entries.

98

99

```typescript { .api }

100

class ZipEntry {

101

name: string;

102

data?: EntryMetaData;

103

id: number;

104

parent?: ZipEntry;

105

uncompressedSize: number;

106

children: ZipEntry[];

107

108

clone(deepClone?: boolean): ZipEntry;

109

getFullname(): string;

110

getRelativeName(ancestor: ZipDirectoryEntry): string;

111

isDescendantOf(ancestor: ZipDirectoryEntry): boolean;

112

isPasswordProtected(): boolean;

113

checkPassword(password: string, options?: EntryGetDataOptions): Promise<boolean>;

114

rename(name: string): void;

115

}

116

```

117

118

### Properties

119

120

- **`name`**: Entry name (without path)

121

- **`data`**: Associated metadata from ZIP file

122

- **`id`**: Unique identifier

123

- **`parent`**: Parent directory

124

- **`uncompressedSize`**: Size of uncompressed content

125

- **`children`**: Child entries (for directories)

126

127

### Methods

128

129

#### getFullname()

130

131

Returns the complete path of the entry.

132

133

```javascript

134

const file = assetsDir.addText("style.css", "body {}");

135

console.log(file.getFullname()); // "assets/style.css"

136

```

137

138

#### getRelativeName()

139

140

Returns the path relative to an ancestor directory.

141

142

```javascript

143

const deepFile = zipFs.find("assets/images/icons/home.png");

144

const assetsDir = zipFs.find("assets");

145

console.log(deepFile.getRelativeName(assetsDir)); // "images/icons/home.png"

146

```

147

148

#### isPasswordProtected()

149

150

Checks if the entry or any of its children requires a password.

151

152

```javascript

153

if (entry.isPasswordProtected()) {

154

const isValid = await entry.checkPassword("secret123");

155

if (isValid) {

156

// Password is correct

157

}

158

}

159

```

160

161

#### rename()

162

163

Changes the name of the entry.

164

165

```javascript

166

const file = zipFs.addText("old-name.txt", "content");

167

file.rename("new-name.txt");

168

console.log(file.getFullname()); // "new-name.txt"

169

```

170

171

## ZipFileEntry Class

172

173

Represents a file in the virtual filesystem.

174

175

```typescript { .api }

176

class ZipFileEntry<ReaderType, WriterType> extends ZipEntry {

177

directory: void;

178

reader: Reader<ReaderType> | ReadableReader | ReadableStream | (Reader<unknown> | ReadableReader | ReadableStream)[];

179

writer: Writer<WriterType> | WritableWriter | WritableStream | AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream>;

180

181

getText(encoding?: string, options?: EntryGetDataOptions): Promise<string>;

182

getBlob(mimeType?: string, options?: EntryGetDataOptions): Promise<Blob>;

183

getData64URI(mimeType?: string, options?: EntryGetDataOptions): Promise<string>;

184

getUint8Array(options?: EntryGetDataOptions): Promise<Uint8Array>;

185

getWritable(writable?: WritableStream, options?: EntryGetDataOptions): Promise<WritableStream>;

186

getData<Type>(writer: Writer<unknown> | WritableWriter | WritableStream | AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream>, options?: EntryGetDataOptions): Promise<Type>;

187

getArrayBuffer(options?: EntryGetDataOptions): Promise<ArrayBuffer>;

188

189

replaceBlob(blob: Blob): void;

190

replaceText(text: string): void;

191

replaceData64URI(dataURI: string): void;

192

replaceUint8Array(array: Uint8Array): void;

193

replaceReadable(readable: ReadableStream): void;

194

}

195

```

196

197

### Data Retrieval Methods

198

199

#### getText()

200

201

Retrieves file content as text.

202

203

```javascript

204

const textFile = zipFs.addText("config.json", '{"key": "value"}');

205

const content = await textFile.getText();

206

const config = JSON.parse(content);

207

```

208

209

#### getBlob()

210

211

Retrieves file content as a Blob.

212

213

```javascript

214

const imageFile = zipFs.addBlob("photo.jpg", photoBlob);

215

const retrievedBlob = await imageFile.getBlob("image/jpeg");

216

```

217

218

#### getData64URI()

219

220

Retrieves file content as a Base64 Data URI.

221

222

```javascript

223

const iconFile = zipFs.addBlob("icon.png", iconBlob);

224

const dataUri = await iconFile.getData64URI("image/png");

225

// Result: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."

226

```

227

228

#### getUint8Array()

229

230

Retrieves file content as raw bytes.

231

232

```javascript

233

const binaryFile = zipFs.addBlob("data.bin", binaryBlob);

234

const bytes = await binaryFile.getUint8Array();

235

console.log(`File size: ${bytes.length} bytes`);

236

```

237

238

### Content Replacement Methods

239

240

#### replaceText()

241

242

Replaces file content with new text.

243

244

```javascript

245

const configFile = zipFs.addText("config.json", '{"version": 1}');

246

configFile.replaceText('{"version": 2}');

247

```

248

249

#### replaceBlob()

250

251

Replaces file content with a new Blob.

252

253

```javascript

254

const imageFile = zipFs.addBlob("old-image.png", oldBlob);

255

imageFile.replaceBlob(newImageBlob);

256

```

257

258

## ZipDirectoryEntry Class

259

260

Represents a directory in the virtual filesystem.

261

262

```typescript { .api }

263

class ZipDirectoryEntry extends ZipEntry {

264

directory: true;

265

266

getChildByName(name: string): ZipEntry | undefined;

267

268

// Adding entries

269

addDirectory(name: string, options?: ZipWriterAddDataOptions): ZipDirectoryEntry;

270

addText(name: string, text: string, options?: ZipWriterAddDataOptions): ZipFileEntry<string, string>;

271

addBlob(name: string, blob: Blob, options?: ZipWriterAddDataOptions): ZipFileEntry<Blob, Blob>;

272

addData64URI(name: string, dataURI: string, options?: ZipWriterAddDataOptions): ZipFileEntry<string, string>;

273

addUint8Array(name: string, array: Uint8Array, options?: ZipWriterAddDataOptions): ZipFileEntry<Uint8Array, Uint8Array>;

274

addHttpContent(name: string, url: string, options?: HttpOptions & ZipWriterAddDataOptions): ZipFileEntry<string, void>;

275

addReadable(name: string, readable: ReadableStream, options?: ZipWriterAddDataOptions): ZipFileEntry<ReadableStream, void>;

276

addFile(file: File, options?: ZipWriterAddDataOptions): Promise<ZipEntry>;

277

addFileSystemEntry(fileSystemEntry: FileSystemEntryLike, options?: ZipWriterAddDataOptions): Promise<ZipEntry[]>;

278

addFileSystemHandle(fileSystemHandle: FileSystemHandleLike, options?: ZipWriterAddDataOptions): Promise<ZipEntry[]>;

279

280

// Importing ZIP files

281

importBlob(blob: Blob, options?: ZipReaderConstructorOptions): Promise<[ZipEntry]>;

282

importData64URI(dataURI: string, options?: ZipReaderConstructorOptions): Promise<[ZipEntry]>;

283

importUint8Array(array: Uint8Array, options?: ZipReaderConstructorOptions): Promise<[ZipEntry]>;

284

importHttpContent(url: string, options?: ZipDirectoryEntryImportHttpOptions): Promise<[ZipEntry]>;

285

importReadable(readable: ReadableStream, options?: ZipReaderConstructorOptions): Promise<[ZipEntry]>;

286

importZip(reader: Reader<unknown> | ReadableReader | ReadableStream | (Reader<unknown> | ReadableReader | ReadableStream)[], options?: ZipReaderConstructorOptions): Promise<[ZipEntry]>;

287

288

// Exporting

289

exportBlob(options?: ZipDirectoryEntryExportOptions): Promise<Blob>;

290

exportData64URI(options?: ZipDirectoryEntryExportOptions): Promise<string>;

291

exportUint8Array(options?: ZipDirectoryEntryExportOptions): Promise<Uint8Array>;

292

exportWritable(writable?: WritableStream, options?: ZipDirectoryEntryExportOptions): Promise<WritableStream>;

293

exportZip(writer: Writer<unknown> | WritableWriter | WritableStream | AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream>, options?: ZipDirectoryEntryExportOptions): Promise<unknown>;

294

}

295

```

296

297

### Navigation

298

299

#### getChildByName()

300

301

Finds a direct child by name.

302

303

```javascript

304

const assetsDir = zipFs.addDirectory("assets");

305

assetsDir.addText("style.css", "body {}");

306

307

const cssFile = assetsDir.getChildByName("style.css");

308

if (cssFile && !cssFile.directory) {

309

const content = await cssFile.getText();

310

}

311

```

312

313

### Adding Content

314

315

#### addDirectory()

316

317

Creates a new subdirectory.

318

319

```javascript

320

const projectDir = zipFs.addDirectory("my-project");

321

const srcDir = projectDir.addDirectory("src");

322

const testDir = projectDir.addDirectory("test");

323

```

324

325

#### addText()

326

327

Adds a text file.

328

329

```javascript

330

const srcDir = zipFs.addDirectory("src");

331

const mainFile = srcDir.addText("main.js", `

332

console.log("Hello, World!");

333

export default function main() {

334

// Application logic

335

}

336

`);

337

```

338

339

#### addBlob()

340

341

Adds a binary file from a Blob.

342

343

```javascript

344

const assetsDir = zipFs.addDirectory("assets");

345

const logoFile = assetsDir.addBlob("logo.png", logoBlob, {

346

lastModDate: new Date(),

347

comment: "Company logo"

348

});

349

```

350

351

#### addHttpContent()

352

353

Adds content fetched from a URL.

354

355

```javascript

356

const libsDir = zipFs.addDirectory("libs");

357

const jqueryFile = libsDir.addHttpContent(

358

"jquery.min.js",

359

"https://code.jquery.com/jquery-3.6.0.min.js",

360

{

361

headers: [["User-Agent", "MyApp/1.0"]]

362

}

363

);

364

```

365

366

#### addFile()

367

368

Adds content from a File object (from file input or drag & drop).

369

370

```javascript

371

// From file input

372

const fileInput = document.querySelector('input[type="file"]');

373

for (const file of fileInput.files) {

374

await zipFs.addFile(file);

375

}

376

```

377

378

### Importing ZIP Archives

379

380

#### importBlob()

381

382

Extracts a ZIP file into the directory.

383

384

```javascript

385

const backupDir = zipFs.addDirectory("backup");

386

await backupDir.importBlob(existingZipBlob);

387

// All entries from existingZipBlob are now in backup/

388

```

389

390

#### importHttpContent()

391

392

Downloads and extracts a ZIP file from a URL.

393

394

```javascript

395

const vendorDir = zipFs.addDirectory("vendor");

396

await vendorDir.importHttpContent(

397

"https://example.com/library-v1.2.3.zip"

398

);

399

```

400

401

### Exporting

402

403

#### exportBlob()

404

405

Exports the directory and its contents as a ZIP Blob.

406

407

```javascript

408

const projectDir = zipFs.addDirectory("my-project");

409

projectDir.addText("README.md", "# My Project");

410

projectDir.addText("package.json", '{"name": "my-project"}');

411

412

const zipBlob = await projectDir.exportBlob({

413

level: 9, // Maximum compression

414

mimeType: "application/zip"

415

});

416

```

417

418

#### exportData64URI()

419

420

Exports as a Base64 Data URI.

421

422

```javascript

423

const dataUri = await zipFs.exportData64URI();

424

// Can be used directly in download links

425

const downloadLink = document.createElement('a');

426

downloadLink.href = dataUri;

427

downloadLink.download = 'archive.zip';

428

```

429

430

## Complete Examples

431

432

### Building a Project Archive

433

434

```javascript

435

import { fs } from "@zip.js/zip.js";

436

437

async function createProjectArchive() {

438

const zipFs = new fs.FS();

439

440

// Create project structure

441

const projectDir = zipFs.addDirectory("my-web-app");

442

const srcDir = projectDir.addDirectory("src");

443

const assetsDir = projectDir.addDirectory("assets");

444

const docsDir = projectDir.addDirectory("docs");

445

446

// Add source files

447

srcDir.addText("index.html", `

448

<!DOCTYPE html>

449

<html>

450

<head><title>My Web App</title></head>

451

<body><h1>Hello World</h1></body>

452

</html>

453

`);

454

455

srcDir.addText("app.js", `

456

document.addEventListener('DOMContentLoaded', () => {

457

console.log('App loaded');

458

});

459

`);

460

461

srcDir.addText("style.css", `

462

body { font-family: Arial, sans-serif; }

463

h1 { color: #333; }

464

`);

465

466

// Add assets

467

await assetsDir.addHttpContent(

468

"jquery.min.js",

469

"https://code.jquery.com/jquery-3.6.0.min.js"

470

);

471

472

// Add documentation

473

docsDir.addText("README.md", `

474

# My Web App

475

476

A simple web application.

477

478

## Getting Started

479

480

Open index.html in a web browser.

481

`);

482

483

docsDir.addText("API.md", `

484

# API Documentation

485

486

## Functions

487

488

- \`init()\` - Initializes the application

489

`);

490

491

// Add project metadata

492

projectDir.addText("package.json", JSON.stringify({

493

name: "my-web-app",

494

version: "1.0.0",

495

description: "A simple web application",

496

main: "src/index.html"

497

}, null, 2));

498

499

// Export with compression

500

const zipBlob = await projectDir.exportBlob({

501

level: 6,

502

comment: "Project created on " + new Date().toISOString()

503

});

504

505

return zipBlob;

506

}

507

```

508

509

### Archive Management System

510

511

```javascript

512

import { fs } from "@zip.js/zip.js";

513

514

class ArchiveManager {

515

constructor() {

516

this.zipFs = new fs.FS();

517

}

518

519

async loadArchive(zipBlob) {

520

await this.zipFs.importBlob(zipBlob);

521

}

522

523

addFolder(path) {

524

const parts = path.split('/');

525

let currentDir = this.zipFs;

526

527

for (const part of parts) {

528

let child = currentDir.getChildByName(part);

529

if (!child) {

530

child = currentDir.addDirectory(part);

531

} else if (!child.directory) {

532

throw new Error(`Path conflict: ${part} is a file`);

533

}

534

currentDir = child;

535

}

536

537

return currentDir;

538

}

539

540

addTextFile(path, content) {

541

const parts = path.split('/');

542

const filename = parts.pop();

543

const dirPath = parts.join('/');

544

545

const dir = dirPath ? this.addFolder(dirPath) : this.zipFs;

546

return dir.addText(filename, content);

547

}

548

549

async addBinaryFile(path, blob) {

550

const parts = path.split('/');

551

const filename = parts.pop();

552

const dirPath = parts.join('/');

553

554

const dir = dirPath ? this.addFolder(dirPath) : this.zipFs;

555

return dir.addBlob(filename, blob);

556

}

557

558

findFile(path) {

559

return this.zipFs.find(path);

560

}

561

562

listFiles(directory = "") {

563

const dir = directory ? this.zipFs.find(directory) : this.zipFs;

564

if (!dir || !dir.directory) return [];

565

566

return dir.children.map(child => ({

567

name: child.name,

568

path: child.getFullname(),

569

isDirectory: child.directory,

570

size: child.uncompressedSize

571

}));

572

}

573

574

async moveFile(fromPath, toPath) {

575

const file = this.zipFs.find(fromPath);

576

if (!file) throw new Error(`File not found: ${fromPath}`);

577

578

const parts = toPath.split('/');

579

const filename = parts.pop();

580

const dirPath = parts.join('/');

581

582

const targetDir = dirPath ? this.addFolder(dirPath) : this.zipFs;

583

584

file.rename(filename);

585

this.zipFs.move(file, targetDir);

586

}

587

588

deleteFile(path) {

589

const file = this.zipFs.find(path);

590

if (file) {

591

this.zipFs.remove(file);

592

return true;

593

}

594

return false;

595

}

596

597

async exportArchive(options = {}) {

598

return await this.zipFs.exportBlob({

599

level: 6,

600

...options

601

});

602

}

603

604

async exportDirectory(path, options = {}) {

605

const dir = this.zipFs.find(path);

606

if (!dir || !dir.directory) {

607

throw new Error(`Directory not found: ${path}`);

608

}

609

return await dir.exportBlob(options);

610

}

611

}

612

613

// Usage

614

const manager = new ArchiveManager();

615

616

// Add files

617

manager.addTextFile("config/app.json", '{"debug": true}');

618

manager.addTextFile("src/main.js", "console.log('Hello');");

619

await manager.addBinaryFile("assets/logo.png", logoBlob);

620

621

// List contents

622

console.log(manager.listFiles()); // Root files

623

console.log(manager.listFiles("src")); // Files in src/

624

625

// Move file

626

await manager.moveFile("config/app.json", "config/production.json");

627

628

// Export specific directory

629

const srcZip = await manager.exportDirectory("src");

630

631

// Export entire archive

632

const fullZip = await manager.exportArchive({

633

level: 9,

634

comment: "Managed archive"

635

});

636

```

637

638

### Incremental Archive Building

639

640

```javascript

641

import { fs } from "@zip.js/zip.js";

642

643

class IncrementalArchiveBuilder {

644

constructor() {

645

this.zipFs = new fs.FS();

646

this.changes = new Set();

647

}

648

649

addContent(path, content, options = {}) {

650

const parts = path.split('/');

651

const filename = parts.pop();

652

653

let currentDir = this.zipFs;

654

for (const part of parts) {

655

let child = currentDir.getChildByName(part);

656

if (!child) {

657

child = currentDir.addDirectory(part);

658

}

659

currentDir = child;

660

}

661

662

let entry;

663

if (typeof content === 'string') {

664

entry = currentDir.addText(filename, content, options);

665

} else if (content instanceof Blob) {

666

entry = currentDir.addBlob(filename, content, options);

667

} else if (content instanceof Uint8Array) {

668

entry = currentDir.addUint8Array(filename, content, options);

669

}

670

671

this.changes.add(path);

672

return entry;

673

}

674

675

updateContent(path, newContent) {

676

const entry = this.zipFs.find(path);

677

if (!entry || entry.directory) {

678

throw new Error(`File not found: ${path}`);

679

}

680

681

if (typeof newContent === 'string') {

682

entry.replaceText(newContent);

683

} else if (newContent instanceof Blob) {

684

entry.replaceBlob(newContent);

685

} else if (newContent instanceof Uint8Array) {

686

entry.replaceUint8Array(newContent);

687

}

688

689

this.changes.add(path);

690

}

691

692

getChangedFiles() {

693

return Array.from(this.changes);

694

}

695

696

async createSnapshot() {

697

const snapshot = await this.zipFs.exportBlob({

698

level: 6,

699

comment: `Snapshot created ${new Date().toISOString()}`

700

});

701

702

this.changes.clear();

703

return snapshot;

704

}

705

706

async createDelta(basePath = null) {

707

if (this.changes.size === 0) return null;

708

709

const deltaFs = new fs.FS();

710

711

for (const changedPath of this.changes) {

712

const entry = this.zipFs.find(changedPath);

713

if (entry && !entry.directory) {

714

const data = await entry.getData(new Uint8ArrayWriter());

715

deltaFs.addUint8Array(changedPath, data);

716

}

717

}

718

719

return await deltaFs.exportBlob({

720

level: 9,

721

comment: `Delta with ${this.changes.size} changes`

722

});

723

}

724

}

725

726

// Usage

727

const builder = new IncrementalArchiveBuilder();

728

729

// Build archive incrementally

730

builder.addContent("v1/app.js", "console.log('v1');");

731

builder.addContent("v1/config.json", '{"version": 1}');

732

733

const v1Snapshot = await builder.createSnapshot();

734

735

// Make changes

736

builder.updateContent("v1/app.js", "console.log('v1.1');");

737

builder.addContent("v1/patch.js", "console.log('patch');");

738

739

const delta = await builder.createDelta();

740

const v1_1Snapshot = await builder.createSnapshot();

741

742

console.log("Changed files:", builder.getChangedFiles());

743

```

744

745

The Filesystem API provides a powerful and intuitive way to work with ZIP files as virtual filesystems, making complex archive operations simple and maintainable.