Edit on val.town ↗

File I/O

There is no direct access to the filesystem in Val Town. This allows us to deploy and scale your code quickly and efficiently. If you need to read files from within a val, you can via the Val Town API.

Docs

import ValTown from "npm:@valtown/sdk";
const vt = new ValTown();
const val_id = "your-val-id-here";
const response = await vt.vals.files.getContent(val_id, {
  path: "path/to/file.txt",
});
const content = await response.text();
console.log(content);

Docs

import ValTown from "npm:@valtown/sdk";
const vt = new ValTown();
const val_id = "your-val-id-here";
const file = await vt.vals.files.create(val_id, {
  path: "path",
  type: "directory",
});

Docs

import ValTown from "npm:@valtown/sdk";
const vt = new ValTown();
const val_id = "your-val-id-here";
const file = await vt.vals.files.update(val_id, {
  path: "path/to/file.txt",
  content: "New file content",
});

Docs

import ValTown from "npm:@valtown/sdk";
const vt = new ValTown();
const val_id = "your-val-id-here";
const files = await Array.fromAsync(
  vt.vals.files.retrieve(id, {
    path: "",
    recursive: true,
  }),
);

Val Town's standard library ships with a suite of utility functions like readFile and serveFile.

Reads the contents of a file from the current val.

Note: you can also import text files, so readFile may be unnecessary and add a round trip.

Signature:

readFile(path: string, metaImportUrl?: string): Promise<string>

Parameters:

Example:

import { readFile } from "https://esm.town/v/std/utils/index.ts";

// Most common usage - reads from current val
const content = await readFile("/README.md");
console.log(content);

// Explicit val specification
const content2 = await readFile("/README.md", import.meta.url);
console.log(content2);

Lists all files in the current val with their metadata.

Signature:

listFiles(metaImportUrl?: string): Promise<File[]>

Parameters:

Example:

import { listFiles } from "https://esm.town/v/std/utils/index.ts";

// Most common usage - lists files from current val
const files = await listFiles();
files.forEach((file) => console.log(file.path));

// Explicit val specification
const files2 = await listFiles(import.meta.url);
files2.forEach((file) => console.log(file.path));

Lists files in a specific directory path within the current val.

Signature:

listFilesByPath(path: string, metaImportUrl?: string): Promise<File[]>

Parameters:

Example:

import { listFilesByPath } from "https://esm.town/v/std/utils/index.ts";

// List files in a specific directory
const frontendFiles = await listFilesByPath("frontend/");
frontendFiles.forEach((file) => console.log(file.path));

Gets the HTTP endpoint URL for a specific file in the val.

Signature:

httpEndpoint(path: string, metaImportUrl?: string): Promise<string>

Parameters:

Example:

import { httpEndpoint } from "https://esm.town/v/std/utils/index.ts";

// Get the HTTP endpoint for a specific file
const endpoint = await httpEndpoint("/api/users.ts");
console.log(endpoint); // Returns the full HTTP URL for the endpoint

Gets the email address for a file with an email trigger in the val.

Note This function only works for the uuid version and not vanity email addresses because that info isn't in our API yet. Open a GitHub feature request if you'd like us to prioritize this.

Signature:

emailAddress(path: string, metaImportUrl?: string): Promise<string>

Parameters:

Example:

import { emailAddress } from "https://esm.town/v/std/utils/index.ts";

// Get the email address for a file with email trigger
const email = await emailAddress("/handlers/processEmail.ts");
console.log(email); // Returns: username-fileid@valtown.email

Notes:

Fetches and transpiles TypeScript/JavaScript code from esm.town URLs.

Signature:

fetchTranspiledJavaScript(url: string): Promise<string>

Example:

import { fetchTranspiledJavaScript } from "https://esm.town/v/std/utils/index.ts";

const code = await fetchTranspiledJavaScript(
  "https://esm.town/v/std/utils/index.ts",
);
console.log(code);

Notes:

Serves a file from the val as an HTTP Response with the correct Content-Type header.

Signature:

serveFile(path: string, metaImportUrl?: string): Promise<Response>

Parameters:

Example:

import { serveFile } from "https://esm.town/v/std/utils/index.ts";

// In a Hono app - most common usage
app.get("/assets/*", async (c) => {
  return await serveFile(c.req.path);
});

// Explicit val specification
app.get("/assets/*", async (c) => {
  return await serveFile(c.req.path, import.meta.url);
});

Determines the appropriate MIME type for a file based on its extension.

Signature:

getContentType(path: string): string

Example:

import { getContentType } from "https://esm.town/v/std/utils/index.ts";

console.log(getContentType("index.html")); // "text/html; charset=utf-8"
console.log(getContentType("script.ts")); // "text/javascript"
console.log(getContentType("data.json")); // "application/json; charset=utf-8"

Features:

Parses Val Town metadata from an import.meta.url.

Signature:

parseVal(importMetaUrl: string): ValMetadata

Example:

import { parseVal } from "https://esm.town/v/std/utils/index.ts";

const val = parseVal(import.meta.url);
console.log(val);
// Output: { owner: "username", name: "valname", ... }

Prior Art:

Creates a Hono-based HTTP server that serves static files from your val. The server automatically serves /index.html for root requests and handles all other file paths.

Signature:

staticHTTPServer(importMetaURL?: string): (request: Request) => Promise<Response>

Parameters:

Example:

import { staticHTTPServer } from "https://esm.town/v/std/utils/index.ts";

// Most common usage - serves files from current val
export default staticHTTPServer();

// Explicit val specification
export default staticHTTPServer(import.meta.url);

Features:

Use Cases:

Notes:

Checks if the current file is the main entry point of the val. This is a replacement for import.meta.main which is not available in Val Town's environment.

Signature:

isMain(importMetaURL: string): boolean

Parameters:

Example:

import { isMain } from "https://esm.town/v/std/utils/index.ts";

if (isMain(import.meta.url)) {
  console.log("This file is being run directly");
  // Run main logic here
} else {
  console.log("This file is being imported");
  // Export functions/classes for use by other files
}

Use Cases:

Notes: