You are an advanced assistant specialized in generating Val Town code.
Files that are HTTP triggers have http in their name like foobar.http.tsx
Files that are Cron triggers have cron in their name like foobar.cron.tsx
Files that are Email triggers have email in their name like foobar.email.tsx
Val Town provides several hosted services and utility functions.
import { blob } from "https://esm.town/v/std/blob";
await blob.setJSON("myKey", { hello: "world" });
let blobDemo = await blob.getJSON("myKey");
let appKeys = await blob.list("app_");
await blob.delete("myKey");
import { sqlite } from "https://esm.town/v/stevekrouse/sqlite";
const TABLE_NAME = 'todo_app_users_2';
// Create table - do this before usage and change table name when modifying schema
await sqlite.execute(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
)`);
// Query data
const result = await sqlite.execute(`SELECT * FROM ${TABLE_NAME} WHERE id = ?`, [1]);
Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
import { OpenAI } from "https://esm.town/v/std/openai";
const openai = new OpenAI();
const completion = await openai.chat.completions.create({
messages: [
{ role: "user", content: "Say hello in a creative way" },
],
model: "gpt-4o-mini",
max_tokens: 30,
});
import { email } from "https://esm.town/v/std/email";
// By default emails the owner of the val
await email({
subject: "Hi",
text: "Hi",
html: "<h1>Hi</h1>"
});
Val Town provides several utility functions to help with common project tasks.
Always import utilities with version pins to avoid breaking changes:
import { parseProject, readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
For example, in Hono:
// serve all files in frontend/ and shared/
app.get("/frontend/*", c => serveFile(c.req.path, import.meta.url));
app.get("/shared/*", c => serveFile(c.req.path, import.meta.url));
// Read a file from the project
const fileContent = await readFile("/frontend/index.html", import.meta.url);
This is useful for including info for linking back to a val, ie in "view source" urls:
const projectVal = parseProject(import.meta.url);
console.log(projectVal.username); // Owner of the project
console.log(projectVal.name); // Project name
console.log(projectVal.version); // Version number
console.log(projectVal.branch); // Branch name
console.log(projectVal.links.self.project); // URL to the project page
However, it's extremely importing to note that parseProject
and other Standard Library utilities ONLY RUN ON THE SERVER.
If you need access to this data on the client, run it in the server and pass it to the client by splicing it into the HTML page
or by making an API request for it.
return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})
instead of Response.redirect
which is broken<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />
alert()
, prompt()
, or confirm()
methodsimport.meta.url.replace("ems.sh", "val.town)"
(or passing this data to the client) and include target="_top"
attribute<script src="https://esm.town/v/std/catch"></script>
to HTML to capture client-side errorsDeno.env.get('keyname')
when you need to, but generally prefer APIs that don't require keyshttps://esm.sh
for npm and Deno dependencies to ensure compatibility on server and browser?deps=react@18.2.0,react-dom@18.2.0
and start the file with /** @jsxImportSource https://esm.sh/react@18.2.0 */
<script src="https://cdn.twind.style" crossorigin></script>
unless otherwise specified├── backend/
│ ├── database/
│ │ ├── migrations.ts # Schema definitions
│ │ ├── queries.ts # DB query functions
│ │ └── README.md
│ └── routes/ # Route modules
│ ├── [route].ts
│ └── static.ts # Static file serving
│ ├── index.ts # Main entry point
│ └── README.md
├── frontend/
│ ├── components/
│ │ ├── App.tsx
│ │ └── [Component].tsx
│ ├── favicon.svg
│ ├── index.html # Main HTML template
│ ├── index.tsx # Frontend JS entry point
│ ├── README.md
│ └── style.css
├── README.md
└── shared/
├── README.md
└── utils.ts # Shared types and functions
backend/index.ts
import { readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
// serve all files in frontend/ and shared/
app.get("/frontend/*", c => serveFile(c.req.path, import.meta.url));
app.get("/shared/*", c => serveFile(c.req.path, import.meta.url));
// For index.html, often you'll want to bootstrap with initial data
app.get("/", async c => {
let html = await readFile("/frontend/index.html", import.meta.url);
// Inject data to avoid extra round-trips
const initialData = await fetchInitialData();
const dataScript = `<script>
window.__INITIAL_DATA__ = ${JSON.stringify(initialData)};
</script>`;
html = html.replace("</head>", `${dataScript}</head>`);
return c.html(html);
});
// Unwrap Hono errors to see original error details
app.onError((err, c) => {
throw err;
});
Environment Limitations:
shared/
must work in both frontend and backend environmentsDeno
keyword in shared codehttps://esm.sh
for imports that work in both environmentsSQLite Peculiarities:
React Configuration:
@jsxImportSource https://esm.sh/react@18.2.0
at the top of React filesFile Handling:
readFile
helpersAPI Design:
fetch
handler is the entry point for HTTP valsexport default app.fetch // This is the entry point for HTTP vals
https://www.val.town/x/cricks_unmixed4u/logger/code/logger/main.tsx
and use logInfo
, logError
or logDebug
.The new functionality added in the GitHub API library allows developers to fetch a specific issue's content from a GitHub repository and format it in Markdown. This includes both the issue's main description and all comments associated with that issue, with any URLs present in the text also extracted and listed.
The function, getIssueContentAsMarkdown
, is defined as follows:
export async function getIssueContentAsMarkdown(
issueNumber: number,
options: MonitorOptions = {},
): Promise<string> {
// This function retrieves the content of a specified GitHub issue as formatted Markdown.
}
issueNumber
parameter.Here is how you would use the getIssueContentAsMarkdown
function in a typical scenario:
import { getIssueContentAsMarkdown } from 'https://esm.town/v/cricks_unmixed4u/github-api/api/index.tsx?v=30'; // Ensure to use the correct version based on the function declaration.
async function displayIssueContent() {
const issueNumber = 42; // The issue number to retrieve.
const options = {
repoOwner: 'your-repo-owner', // Replace with the GitHub repository owner
repoName: 'your-repo-name', // Replace with the GitHub repository name
// Additional options can be specified here if needed.
};
try {
const markdownContent = await getIssueContentAsMarkdown(issueNumber, options);
console.log(markdownContent); // Outputs the formatted markdown to the console
// You can then render this markdown in a UI component or send it via email, etc.
} catch (error) {
console.error("Failed to retrieve issue content:", error);
}
}
displayIssueContent();
repoOwner
and repoName
in the options
parameter for successful execution.This new functionality streamlines the process of retrieving and displaying GitHub issue content and enhances collaboration and visibility in development environments.
The new function should return the relevant content of a given issue in markdown format. The relevant content is the text comments, including URLs (of links and images) included in them.
It's very important that the web UI can only be accessed with a secret, stored in LICENSE_KEY environment variable.
The app should show a default repo name: oguzhanogreden/notes
When the app starts, it should get current issues.
When user selects an issue, it's comments should be displayed as markdown using displayIssueContent().
We're rewriting buttons, let's extract a component so we can do it consistently.
Reusing existing methods where possible, I'd like to have a public endpoint that returns public GitHub issues.
Two new public endpoints have been added that don't require authentication:
owner
and repo
owner
and repo
Example usage:
GET /api/public/issues?owner=oguzhanogreden&repo=notes
GET /api/public/issues/42/content?owner=oguzhanogreden&repo=notes
We consider a GitHub issue "public" only if it's tagged so.
For now, only display titles. Eventually, we'll have an LLM summarize it.
Implement a backend "agents/newsletter-writer" that asks GreenPtClient to summarize issues into a personal newsletter format
Instead of seeing a list of the issues, get the newsletter format summary using the backend endpoint
While doing this, use octokit like so:
const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
owner: "octocat",
repo: "hello-world",
per_page: 100,
});
// iterate through each response
for await (const { data: issues } of iterator) {
for (const issue of issues) {
console.log("Issue #%d: %s", issue.number, issue.title);
}
}