11It would be awesome if we built a fork of these downtime detectors that also stored historical uptime/downtime (and possibly latency) information in sqlite, and then provided an http interface to view the data as well.
1213### Free Stock API Proxy
1415I have been working on a stock price api tool, initially for use within Google Sheets: https://www.val.town/v/stevekrouse/stockPrice
1617It would be awesome to expand this to also be useful to other folks, ie folks within Val Town. For example, it could be used to build stock price trackers. Our [BTC price tracker](https://www.val.town/v/stevekrouse/btcPriceAlert) is pretty popular. I think one for stocks would be similarly popular, but it'd need someone to provide a good free stock API. Maybe one exists or maybe we need to proxy it.
1819
key_safe_linkREADME.md2 matches
1# One-click environment variable
23Copying and pasting secret API keys into your Val Town [Environment Variables](https://www.val.town/settings/environment-variables) is annoying and error prone. Wouldn't it be nice if you could add an environment variable in one click? What could such a protocol look like for third-party API company to be able to safely pass their customer's API keys to their customer's Val Town account.
45A naive approach to this would be a link that looks like this:
11```
1213However it isn't safe to put API key values in URLs like that, but it would be great if we could still put it in the URL so it can act like a simple link. We need to encrypt the API key in such a way that nobody can read it except for the Val Town app. Val Town could provide a public key for API providers to encrypt their tokens with.
1415We could add an extra layer of security by including the timestamp in the request as well as the Val Town username that the token is intended for. All that data should be included in the encrypted package. We can also ensure that each such link is used exactly once.
weatherGPTmain.tsx1 match
12baseURL: PORTKEY_GATEWAY_URL,
13defaultHeaders: createHeaders({
14apiKey: Deno.env.get("PORTKEY_API_KEY"),
15virtualKey: Deno.env.get("PORTKEY_OPENAI_VIRTUAL_KEY"),
16}),
1This val is part of the SteamPlaytimeHistory project which consists of logging your recently played games on steam everyday through valve's API.
23I wanted to log this data so I can analyse which days do I game the most ? which periods do I log the most hours in my confort game (Dead By Daylight) ? And so on. I think the data viz possibilities are super interesting, just like when Valve releases the "Steam in review" at the end of the year
45This val fetches your recent playtime history from valve's API and stores it in a database every day !
67The project uses multiple vals to work:
15To run this project, you'll need:
1617- A steam web api key: https://steamcommunity.com/login/home/?goto=%2Fdev%2Fapikey
18- SteamID of the user (profile needs to be public)
19- Discord websocket url (for error messages)
blob_adminREADME.md1 match
9[](https://www.val.town/v/stevekrouse/blob_admin_app/fork)
1011It uses [basic authentication](https://www.val.town/v/pomdtr/basicAuth) with your [Val Town API Token](https://www.val.town/settings/api) as the password (leave the username field blank).
1213# TODO
gameIdeaApimain.tsx19 matches
1import { blob } from "https://esm.town/v/std/blob";
2import { extractHttpEndpoint } from "https://esm.town/v/xkonti/extractHttpEndpoint?v=2";
3import { GptApi } from "https://esm.town/v/xkonti/gptApiFramework?v=67";
4import { z } from "npm:zod";
56const api = new GptApi({
7url: extractHttpEndpoint(import.meta.url).toLowerCase(),
8title: "Video Game Idea API",
9description: "The API for submitting fun Video Game Ideas",
10version: "1.0.0",
11policyGetter: async () => {
28}).describe("A Video Game Idea returned in exchange for the submitted one");
2930api.jsonToJson({
31verb: "post",
32path: "/submission",
35requestSchema: IdeaSubmissionSchema,
36responseSchema: IdeaResponseSchema,
37}, async (ctx, input, apiKey) => {
38if (apiKey == null || apiKey !== Deno.env.get("GPT_GAME_IDEA_API_KEY")) {
39return {
40idea: "",
61: {
62idea: "Please come up with some cool idea for the user. There is nothing in the database yet.",
63author: "API Server",
64};
6579});
8081export default api.serve();
8283// Idea management
105}
106107const privacyPolicy = `# Video Game Idea API Privacy Policy
108Last Updated: 2024-05-19
109110## 1. Introduction
111Welcome to Video Game Idea API. This privacy policy outlines our practices regarding the collection, use, and sharing of information through Video Game Idea API.
112113## 2. Data Collection and Use
114Video Game Idea API allows users to store, retrieve, list, and delete data. The data stored can be of any type as inputted by the user. We do not restrict or control the content of the data stored. Video Game Idea API serves as a public database accessible to anyone with an API key. The API is not intended for storing any personal data.
115116## 3. User Restrictions
117Video Game Idea API does not impose age or user restrictions. However, the API is not intended for use by children under the age of 13. Users are advised to consider the sensitivity of the information they share.
118119## 4. Global Use
120Our API is accessible globally. Users from all regions can store and access data on Video Game Idea API.
121122## 5. Data Management
123Given the nature of Video Game Idea API, there are no user accounts or user identification measures. The API operates like a public database where data can be added, viewed, and deleted by any user. Users should be aware that any data they input can be accessed, modified, or deleted by other users.
124125## 6. Data Security
126Video Game Idea API is protected by an API key; beyond this, there is no specific data security measure in place. Users should not store sensitive, personal, or confidential information using Video Game Idea API. User's ideas are stored in a secure manner and are not shared with any third parties. We assume no responsibility for the security of the data stored.
127128## 7. Third-Party Involvement
129The API code is run and data is stored by val.town. They act as a third-party service provider for Video Game Idea API.
130131## 8. Use Restrictions
132The API is not intended for use in any mission-critical applications. By submitting ideas, users are responsible for the content they submit. The ideas submitted by the user will be considered public domain.
133134## 9. Disclaimer
135The API is provided as-is without any guarantees.
136137## 10. Changes to This Policy
gptApiTemplatemain.tsx13 matches
1import { blob } from "https://esm.town/v/std/blob";
2import { extractHttpEndpoint } from "https://esm.town/v/xkonti/extractHttpEndpoint?v=2";
3import { GptApi } from "https://esm.town/v/xkonti/gptApiFramework?v=67";
4import { z } from "npm:zod";
56// Configure API
78const api = new GptApi({
9url: extractHttpEndpoint(import.meta.url).toLowerCase(),
10title: "API Name",
11description: "The API for submitting fun Video Game Ideas",
12version: "1.0.0",
13policyGetter: async () => {
27}).describe("Description of the output");
2829api.jsonToJson({
30verb: "post",
31path: "/example",
34requestSchema: InputSchema,
35responseSchema: OutputSchema,
36}, async (ctx, input, apiKey) => {
37// Implementation of the /example endpoint
38return {
41});
4243// Serve the API
44export default api.serve();
4546// Privacy policy template in Markdown
47const privacyPolicy = `# <apiName> Privacy Policy
48Last Updated: <lastUpdated>
4950## 1. Introduction
51Welcome to <apiName>. This privacy policy outlines our practices regarding the collection, use, and sharing of information through <apiName>.
5253## 2. Data Collection and Use
54<apiName> allows users to store, retrieve, list, and delete data. The data stored can be of any type as inputted by the user. We do not restrict or control the content of the data stored. The API operates as a public database, where data can be accessed by any user. We do not tie or track data per user.
5556## 3. Data Security
57<apiName> is protected by an API key. Users should be aware that any data they input can be accessed, modified, or deleted by other users with access to the API key. Users are advised not to store sensitive, personal, or confidential information. We assume no responsibility for the security of the data stored. The API code is run and data is stored by val.town, a third-party service provider.
5859## 4. Changes to This Policy
extractHttpEndpointREADME.md1 match
45```typescript
6const apiUrl = extractHttpEndpoint(import.meta.url);
7```
gptApiFrameworkmain.tsx43 matches
5556/**
57* The API info object that is used to describe the API to the GPT.
58*/
59export interface ApiInfo {
60/**
61* The URL of the API. This should match the URL of your Val.
62*/
63url: string;
6465/**
66* The name of the API. It gives the GPT an idea about the purpose of the API.
67*/
68title: string;
6970/**
71* A short description of the API. It gives the GPT an idea about the purpose of the API.
72*/
73description: string;
7475/**
76* The version of the API. Required by the OpenAPI spec.
77*/
78version: string;
93return zodToJsonSchema(schema, {
94name: "schema",
95target: "openApi3",
96}).definitions?.schema ?? null;
97}
125126/**
127* Describes the paths of an OpenAPI spec.
128*/
129type Paths = {
136137/**
138* Assembles the paths of an OpenAPI spec from endpoint definitions.
139* @param endpoints The endpoint definitions to use.
140* @returns The paths of the OpenAPI spec.
141*/
142function getPathsDesc(endpoints: EndpointDefinition[]): Paths {
178179/**
180* Generates an OpenAPI spec for the defined API.
181* @param url The URL of the API.
182* @param title The title of the API.
183* @param description The description of the API.
184* @param version The version of the API.
185* @param endpoints The endpoint definitions to use.
186* @returns The OpenAPI spec.
187*/
188function getOpenApiSpec(
189url: string,
190title: string,
194) {
195return {
196openapi: "3.1.0",
197info: {
198title,
210211/**
212* A class representing a GPT API. It provides methods for registering
213* endpoints and serving the API.
214*/
215export class GptApi {
216private app = new Hono();
217private info: ApiInfo;
218private endpoints: EndpointDefinition[] = [];
219220/**
221* Creates a new GptApi instance.
222* @param info Configuration for the API.
223*/
224constructor(info: ApiInfo) {
225this.info = info;
226this.app.get("/gpt/schema", (ctx) => {
227const spec = getOpenApiSpec(
228this.info.url,
229this.info.title,
250251this.app.get("/", (ctx) => {
252return ctx.text(`OpenAPI spec: ${this.info.url}/gpt/schema\nPrivacy policy: ${this.info.url}/privacypolicy\n`);
253});
254}
262jsonToNothing<TRequestSchema extends z.Schema>(
263endpointDef: InEndpointDefinition<TRequestSchema>,
264handler: (ctx: Context, reqBody: z.infer<TRequestSchema>, apiKey: string | null) => Promise<number>,
265) {
266const handlerWrapper = async (ctx: Context) => {
271// TODO: Handle invalid data format
272273const apiKey = this.extractApiKey(ctx);
274const statusCode = await handler(ctx, parsedRequestData, apiKey);
275return ctx.body(null, statusCode as StatusCode);
276};
294nothingToJson<TResponseSchema extends z.Schema>(
295endpointDef: OutEndpointDefinition<TResponseSchema>,
296handler: (ctx: Context, apiKey: string | null) => Promise<z.infer<TResponseSchema>>,
297) {
298const handlerWrapper = async (ctx: Context) => {
299const apiKey = this.extractApiKey(ctx);
300const response = await handler(ctx, apiKey);
301302// Validate response data
327ctx: Context,
328reqBody: z.infer<TRequestSchema>,
329apiKey: string | null,
330) => Promise<z.infer<TResponseSchema>>,
331) {
338// TODO: Handle invalid data format
339340const apiKey = this.extractApiKey(ctx);
341const response = await handler(ctx, parsedRequestData, apiKey);
342343// Validate response data
388389/**
390* Returns a function that can be used to serve the API.
391*
392* @example ValTown usage:
393* ```ts
394* export default gptApi.serve();
395* ```
396*
397* @example Deno usage:
398* ```
399* const { fetch } = gptApi.serve();
400* export default { fetch };
401* ```
406407/**
408* Extracts API key from Bearer Auth header.
409*/
410private extractApiKey(ctx: Context): string | null {
411const authHeader = ctx.req.header("Authorization");
412if (!authHeader || !authHeader.startsWith("Bearer ")) {
414}
415416const apiKey = authHeader.split(" ")[1];
417return apiKey;
418}
419}
maroonArmadilloREADME.md1 match
1# Hono
23Here's an example using the [Hono](https://hono.dev/) server library with the [Web API](https://docs.val.town/api/web). It works great!
45