Back to packages list

Vals using ky

Description from the NPM package:
Tiny and elegant HTTP client based on the browser Fetch API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { jwkToDidKey } from "https://esm.town/v/vladimyr/jwkToDidKey";
import ky from "npm:ky";
let jwk, did, resolvedJwk;
// @see: https://w3c-ccg.github.io/did-method-key/#example-5
jwk = {
kty: "OKP",
crv: "Ed25519",
x: "O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp");
resolvedJwk = await resolveDid(did);
console.log(JSON.stringify(resolvedJwk));
console.assert(jwk.kty === resolvedJwk.kty);
console.assert(jwk.crv === resolvedJwk.crv);
console.assert(jwk.x === resolvedJwk.x);
if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
jwk = {
kty: "OKP",
crv: "Ed25519",
x: "TLWr9q15-_WrvMr8wmnYXNJlHtS4hbWGnyQa7fCluik",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG");
resolvedJwk = await resolveDid(did);
console.log(JSON.stringify(resolvedJwk));
console.assert(jwk.kty === resolvedJwk.kty);
console.assert(jwk.crv === resolvedJwk.crv);
console.assert(jwk.x === resolvedJwk.x);
if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
jwk = {
kty: "OKP",
crv: "Ed25519",
x: "dCK5iHWYBo4yxESKlJrbKQ0PTjW54BsO5fGh5gD-JnQ",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf");
resolvedJwk = await resolveDid(did);
console.log(JSON.stringify(resolvedJwk));
console.assert(jwk.kty === resolvedJwk.kty);
console.assert(jwk.crv === resolvedJwk.crv);
console.assert(jwk.x === resolvedJwk.x);
if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
console.log("---");
jwk = {
kty: "OKP",
crv: "X25519",
x: "L-V9o0fNYkMVKNqsX7spBzD_9oSvxM_C7ZCZX1jLO3Q",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F");
// resolvedJwk = await resolveDid(did);
// console.log(JSON.stringify(resolvedJwk));
// console.assert(jwk.kty === resolvedJwk.kty);
// console.assert(jwk.crv === resolvedJwk.crv);
// console.assert(jwk.x === resolvedJwk.x);
// if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
jwk = {
kty: "OKP",
crv: "X25519",
x: "_TOE4TKtAqVsePRVR-5AA43HkAK5DSntkOCO7nYq5xU",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha");
// resolvedJwk = await resolveDid(did);
// console.log(JSON.stringify(resolvedJwk));
// console.assert(jwk.kty === resolvedJwk.kty);
// console.assert(jwk.crv === resolvedJwk.crv);
// console.assert(jwk.x === resolvedJwk.x);
// if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
jwk = {
kty: "OKP",
crv: "X25519",
x: "rYxIwmdlrqetxTYolgXBq-qVBQCT29IYyWq9JIGgNWU",
} as const;
did = jwkToDidKey(jwk);
console.log(did);
console.assert(did === "did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ");
// resolvedJwk = await resolveDid(did);
// console.log(JSON.stringify(resolvedJwk));
// console.assert(jwk.kty === resolvedJwk.kty);
// console.assert(jwk.crv === resolvedJwk.crv);
// console.assert(jwk.x === resolvedJwk.x);
// if (jwk.y) console.assert(jwk.y === resolvedJwk.y);
console.log("---");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// SPDX-License-Identifier: 0BSD
import { id_rsaEncryption, RSAPublicKey } from "npm:@peculiar/asn1-rsa";
import { AsnParser, AsnSerializer } from "npm:@peculiar/asn1-schema";
import { AlgorithmIdentifier, SubjectPublicKeyInfo } from "npm:@peculiar/asn1-x509";
import ky from "npm:ky";
import { base64pad } from "npm:multiformats/bases/base64";
import * as v from "npm:valibot";
const ActorSchema = v.object({
publicKey: v.object({
id: v.string(),
publicKeyPem: v.string(),
}),
});
const data = await ky.get("https://mastodon.social/@Mastodon.json").json();
const { publicKey } = v.parse(ActorSchema, data);
console.log("keyId=%s\n", publicKey.id);
console.log("Public key in SPKI format:\n%s", publicKey.publicKeyPem.trim());
console.log();
const spki = AsnParser.parse(
parsePem(publicKey.publicKeyPem),
SubjectPublicKeyInfo,
);
console.log("SPKI structure:\n%o", spki);
const expectedAlgo = new AlgorithmIdentifier({
algorithm: id_rsaEncryption,
parameters: null,
});
const actualAlgo = spki.algorithm;
console.assert(expectedAlgo.isEqual(actualAlgo));
console.log();
const pkcs1 = AsnParser.parse(spki.subjectPublicKey, RSAPublicKey);
console.log("PKCS #1 structure (SubjectPublicKeyInfo::subjectPublicKey):\n%o", pkcs1);
console.log();
console.log("Public key in PKCS #1 format:");
const bytes = new Uint8Array(AsnSerializer.serialize(pkcs1));
const rsaPublicKeyPem = [
"-----BEGIN RSA PUBLIC KEY-----",
wrap(base64pad.baseEncode(bytes), 64),
"-----END RSA PUBLIC KEY-----",
].join("\n");
console.log(rsaPublicKeyPem);
function parsePem(pem: string) {
pem = pem.replace(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, "");
return base64pad.baseDecode(pem);
}
function wrap(input: string, columns = 64) {
const reLines = new RegExp(`.{${columns}}`, "g");
return input.replace(reLines, (line) => line + "\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
import { fetch as fetch_ } from "https://esm.town/v/std/fetch?v=4";
import { fetch } from "https://esm.town/v/vladimyr/fetch";
import ky from "npm:ky";
const ip = await ky("https://httpbun.com/ip.json", { fetch }).json();
console.log(ip);
{
console.log();
const ip = await ky("https://httpbun.com/ip.json", { fetch: fetch_ }).json();
console.log(ip);
}

Kysely on val.town

Uses @easrng/kyselyVtDialect as a Kysely Dialect and @easrng/kyselyVtTypes for type autogeneration.

Readme
1
2
3
4
5
6
7
8
9
10
11
import type { DB } from "https://easrng-kyselyvttypes.web.val.run/?tables=contacts";
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("contacts").selectAll().execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);

Val Shot

Generate val source code screenshot using sourcecodeshots.com

⚠️ This service is offered for personal use under a reasonable usage policy as stated here: https://sourcecodeshots.com/docs

📣 Special thanks to @pomdtr for their help and contributions!

Usage

https://vladimyr-valshot.web.val.run/v/<author>/<val>

Example

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// SPDX-License-Identifier: 0BSD
import { fetchVal } from "https://esm.town/v/vladimyr/fetchVal";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { toHonoHandler } from "https://esm.town/v/vladimyr/toHonoHandler";
import { Hono } from "npm:hono";
import ky from "npm:ky";
const router = new Hono();
// router.get("/", toHonoHandler(serveReadme(import.meta.url)));
router.get("/", async (c) => {
// const { author, name } = c.req.param();
const query = c.req.query();
const res = await fetch(
"https://raw.githubusercontent.com/burningion/dab-and-tpose-controlled-lights/master/src/dab-tpose-controller.py",
);
const code = await res.text();
const imageURL = await createScreenshot(code, query.theme);
return c.redirect(imageURL.href);
});
export default router.fetch;
export async function createScreenshot(code: string, theme: string = "dark-plus"): Promise<URL> {
const apiUrl = "https://sourcecodeshots.com/api/image/permalink";
const { url } = await ky.post(apiUrl, {
json: {
code,
settings: { language: "python", theme },
},
}).json();
return new URL(url);
}

Try on Val Town

This service enables quick generation of new val with specified jsr package. Package authors can provide custom examples by setting either:

  • valtownExample property of jsr.json/deno.json to contain example js/ts code
  • valtownExampleFilename property of jsr.json/deno.json to point to the file with example js/ts code

If no example is found val will be created with the default snippet, using @luca/flag as an example :

Create valimport * as flag from "jsr:@luca/flag";

Go ahead ↗️ try it (on Val Town)! 🎉

Additionally, the service supports ?code=<base64code> query param that allows overriding extracted/generated example code. For example one might want to override @luca/flag's snippet with:

Create valimport { printProgress } from "jsr:@luca/flag@1"; printProgress();

In order to do so first you need to convert it to base64:

$ printf 'import { printProgress } from "jsr:@luca/flag@1";\n\nprintProgress();' | base64 -w0
# ==> aW1wb3J0IHsgcHJpbnRQcm9ncmVzcyB9IGZyb20gImpzcjpAbHVjYS9mbGFnQDEiOwoKcHJpbnRQcm9ncmVzcygpOw==

Then you simply construct the URL by setting the returned value to code query param:
↗️ https://vladimyr-jsr.web.val.run?code=aW1wb3J0IHsgcH...

Usage

  • https://vladimyr-jsr.web.val.run/<scope>/<name>[@<version>]
  • https://vladimyr-jsr.web.val.run?code=<base64code>

Example

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// SPDX-License-Identifier: 0BSD
import { getConfig } from "https://esm.town/v/vladimyr/jsrApi";
import { newValURL } from "https://esm.town/v/vladimyr/newValURL";
import { type HtmlProcessor, serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import ky from "npm:ky";
export default async function(req: Request, options?: {
transformReadme: HtmlProcessor;
}): Promise<Response> {
const { pathname, searchParams } = new URL(req.url);
let code = searchParams.get("code");
if (code) {
const url = newValURL();
url.searchParams.set("code64", code);
return Response.redirect(url);
}
if (pathname === "/") {
return serveReadme(import.meta.url, options?.transformReadme)();
}
const [scope, name, version = "latest"] = pathname.split(/[/@]/g).filter(Boolean);
if (!scope || !name) {
return Response.redirect(newValURL());
}
let example;
try {
example = await fetchValtownExample(scope, name, version);
} catch {}
if (example) {
return Response.redirect(newValURL(example));
}
let importSpec;
if (version !== "latest") {
importSpec = `jsr:@${scope}/${name}@${version}`;
} else {
importSpec = `jsr:@${scope}/${name}`;
}
code = `import * as ${name} from "${importSpec}";`;
return Response.redirect(newValURL(code));
}
async function fetchValtownExample(scope: string, name: string, version: string) {
const pkgConfig = await getConfig(scope, name, version);
version = pkgConfig.version;
if (pkgConfig.valtownExample) {
return pkgConfig.valtownExample;
}
if (!pkgConfig.valtownExampleFilename) {
return;
}
const exampleFile = new URL(`file://${pkgConfig.valtownExampleFilename}`).pathname.slice(1);
return ky.get(exampleFile, {
prefixUrl: new URL(`https://jsr.io/@${scope}/${name}/${version}/`),
}).text();
}

Kysely type generator for @std/sqlite

Usage

  • Fork to your account.
  • Update allowedTables to expose any tables you'd like to import the schema of.
    This will make their schemas public!
  • Add import type { DB } from "https://yourusername-kyselyVtTypes.web.val.run/?tables=tables,you,need" to your program. See that QueryParams` type at the top? Add those to your URL to set more options.

Demo

See @easrng/kyselyVtDemo.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
type QueryParams = {
camelCase?: "true" | "false";
excludePattern?: string;
includePattern?: string;
runtimeEnums?: "true" | "false";
schema?: string;
typeOnlyImports?: "true" | "false";
tables: string; // comma separated
allowTables?: "true" | "false";
};
const allowedTables: string[] = [];
import { escape as escapeRegex } from "https://deno.land/std@0.221.0/regexp/escape.ts";
import * as codegen from "https://esm.sh/kysely-codegen@0.14.2?alias=git-diff:lodash.noop,pg:lodash.noop,fs:lodash.noop,mysql2:lodash.noop,kysely-bun-worker:lodash.noop,better-sqlite3:lodash.noop,@libsql/kysely-libsql:lodash.noop,dotenv:lodash.noop,dotenv-
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@^0.27.3";
class CodegenVtDialect extends codegen.Dialect {
readonly adapter: codegen.SqliteAdapter;
readonly introspector: codegen.SqliteDialect["introspector"];
constructor() {
super();
const d = new codegen.SqliteDialect();
this.adapter = d.adapter;
this.introspector = d.introspector;
}
async createKyselyDialect() {
return new VtDialect();
}
}
type GenerateOptions = {
camelCase?: boolean;
excludePattern?: string;
includePattern?: string;
runtimeEnums?: boolean;
schema?: string;
typeOnlyImports?: boolean;
tables: string[];
allowTables?: boolean;
};
function parseOptions(params: URLSearchParams): GenerateOptions {
const camelCase = params.has("camelCase") ? params.get("camelCase") === "true" : undefined;
const excludePattern = params.get("excludePattern") ?? undefined;
const includePattern = params.get("includePattern") ?? undefined;
const runtimeEnums = params.has("runtimeEnums") ? params.get("runtimeEnums") === "true" : undefined;
const schema = params.get("schema") ?? undefined;
const typeOnlyImports = params.has("typeOnlyImports") ? params.get("typeOnlyImports") === "true" : undefined;
const tables = params.get("tables")?.split(",")?.map(e => e.trim()) ?? [];
const allowTables = params.has("allowTables") ? params.get("allowTables") === "true" : undefined;
return {
camelCase,
excludePattern,
includePattern,
runtimeEnums,
schema,
typeOnlyImports,
tables,
allowTables,
};
}
export default async function(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname !== "/") return new Response(null, { status: 404 });
if (req.method !== "GET") return new Response(null, { status: 405 });
if (
[
"object",
"iframe",
"frame",
"fencedframe",
"embed",
"document",
].includes(req.headers.get("sec-fetch-dest"))
)
return new Response(
"This endpoint returns TypeScript. Usage:\n```ts\nimport type { DB } from " + JSON.stringify(req.url) + "\n```",
);
try {
const options = parseOptions(url.searchParams);
const notAllowed = [];
for (const table of options.tables) {
if (options.allowTables) { allowedTables.push(table); }
if (!allowedTables.includes(table)) {
notAllowed.push(table);
}
}
if (notAllowed.length > 0) {
throw new Error("some tables you requested are not public: " + notAllowed.join(", "));
}
const db = new Kysely({
dialect: new VtDialect(),
});
const dialectInstance = new CodegenVtDialect();
const metadata = await dialectInstance.introspector.introspect({
db: db,
// this is a minimatch pattern, but the strings are not user-controlled so it should be ok
includePattern: "{" + options.tables.map(e => e).join(",") + ",}",
});
const transformer = new codegen.Transformer();
const nodes = transformer.transform({
camelCase: !!options.camelCase,
1
2
3
4
5
6
7
8
9
10
11
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import type { DB } from "https://nbbaier-kyselyVtTypes.web.val.run/?tables=users";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("users").selectAll().where("id", "=", "1").execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);

Kysely on val.town

Uses @easrng/kyselyVtDialect as a Kysely Dialect and @easrng/kyselyVtTypes for type autogeneration.

Readme
1
2
3
4
5
6
7
8
9
10
11
import type { DB } from "https://easrng-kyselyvttypes.web.val.run/?tables=contacts";
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("contacts").selectAll().execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);

Kysely type generator for @std/sqlite

Usage

  • Fork to your account.
  • Update allowedTables to expose any tables you'd like to import the schema of.
    This will make their schemas public!
  • Add import type { DB } from "https://yourusername-kyselyVtTypes.web.val.run/?tables=tables,you,need" to your program. See that QueryParams` type at the top? Add those to your URL to set more options.

Demo

See @easrng/kyselyVtDemo.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
type QueryParams = {
camelCase?: "true" | "false";
excludePattern?: string;
includePattern?: string;
runtimeEnums?: "true" | "false";
schema?: string;
typeOnlyImports?: "true" | "false";
tables: string; // comma separated
};
const allowedTables: string[] = ["contacts"];
import { escape as escapeRegex } from "https://deno.land/std@0.221.0/regexp/escape.ts";
import * as codegen from "https://esm.sh/kysely-codegen@0.14.2?alias=git-diff:lodash.noop,pg:lodash.noop,fs:lodash.noop,mysql2:lodash.noop,kysely-bun-worker:lodash.noop,better-sqlite3:lodash.noop,@libsql/kysely-libsql:lodash.noop,dotenv:lodash.noop,dotenv-
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@^0.27.3";
class CodegenVtDialect extends codegen.Dialect {
readonly adapter: codegen.SqliteAdapter;
readonly introspector: codegen.SqliteDialect["introspector"];
constructor() {
super();
const d = new codegen.SqliteDialect();
this.adapter = d.adapter;
this.introspector = d.introspector;
}
async createKyselyDialect() {
return new VtDialect();
}
}
type GenerateOptions = {
camelCase?: boolean;
excludePattern?: string;
includePattern?: string;
runtimeEnums?: boolean;
schema?: string;
typeOnlyImports?: boolean;
tables: string[];
};
function parseOptions(params: URLSearchParams): GenerateOptions {
const camelCase = params.has("camelCase") ? params.get("camelCase") === "true" : undefined;
const excludePattern = params.get("excludePattern") ?? undefined;
const includePattern = params.get("includePattern") ?? undefined;
const runtimeEnums = params.has("runtimeEnums") ? params.get("runtimeEnums") === "true" : undefined;
const schema = params.get("schema") ?? undefined;
const typeOnlyImports = params.has("typeOnlyImports") ? params.get("typeOnlyImports") === "true" : undefined;
const tables = params.get("tables")?.split(",")?.map(e => e.trim()) ?? [];
return {
camelCase,
excludePattern,
includePattern,
runtimeEnums,
schema,
typeOnlyImports,
tables,
};
}
export default async function(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname !== "/") return new Response(null, { status: 404 });
if (req.method !== "GET") return new Response(null, { status: 405 });
if (
[
"object",
"iframe",
"frame",
"fencedframe",
"embed",
"document",
].includes(req.headers.get("sec-fetch-dest"))
)
return new Response(
"This endpoint returns TypeScript. Usage:\n```ts\nimport type { DB } from " + JSON.stringify(req.url) + "\n```",
);
try {
const options = parseOptions(url.searchParams);
const notAllowed = [];
for (const table of options.tables) {
if (!allowedTables.includes(table)) {
notAllowed.push(table);
}
}
if (notAllowed.length > 0) {
throw new Error("some tables you requested are not public: " + notAllowed.join(", "));
}
const db = new Kysely({
dialect: new VtDialect(),
});
const dialectInstance = new CodegenVtDialect();
const metadata = await dialectInstance.introspector.introspect({
db: db,
// this is a minimatch pattern, but the strings are not user-controlled so it should be ok
includePattern: "{" + options.tables.map(e => e).join(",") + ",}",
});
const transformer = new codegen.Transformer();
const nodes = transformer.transform({
camelCase: !!options.camelCase,
defaultSchema: options.schema,
dialect: dialectInstance,
metadata,
runtimeEnums: !!options.runtimeEnums,
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// SPDX-License-Identifier: 0BSD
import ky from "npm:ky";
import stripJsonComments from "npm:strip-json-comments";
import * as v from "npm:valibot";
const client = ky.create({ prefixUrl: "https://jsr.io" });
const configFiles = [
"jsr.json",
"jsr.jsonc",
"deno.json",
"deno.jsonc",
];
// @see: https://jsr.io/docs/api#package-metadata
const PkgMetaSchema = v.object({
scope: v.string(),
name: v.string(),
latest: v.string(),
});
// @see: https://jsr.io/docs/api#package-version-metadata
const PkgVerMetaSchema = v.object({
manifest: v.record(
v.string([v.startsWith("/")]),
v.object({
size: v.number([v.integer(), v.minValue(0)]),
checksum: v.string([v.startsWith("sha")]),
}),
),
});
// @see: https://jsr.io/docs/package-configuration
const PkgConfSchema = v.object({
name: v.string(),
version: v.string(),
valtownExample: v.optional(v.string()),
valtownExampleFilename: v.optional(v.string()),
});
export async function getLatestVersion(scope: string, name: string) {
scope = normalizeScope(scope);
const data = await client.get(`@${scope}/${name}/meta.json`).json();
return v.parse(PkgMetaSchema, data).latest;
}
export async function getManifest(scope: string, name: string, version = "latest") {
scope = normalizeScope(scope);
if (version === "latest") {
version = await getLatestVersion(scope, name);
}
const data = await client.get(`@${scope}/${name}/${version}_meta.json`).json();
return v.parse(PkgVerMetaSchema, data).manifest;
}
export async function getConfig(scope: string, name: string, version: string) {
scope = normalizeScope(scope);
const manifest = await getManifest(scope, name, version);
const configFile = configFiles.find(filename => Object.hasOwn(manifest, `/${filename}`));
const data = await client.get(`@${scope}/${name}/${version}/${configFile}`, {
parseJson: (text) => JSON.parse(stripJsonComments(text)),
}).json();
return v.parse(PkgConfSchema, data);
}
function normalizeScope(input: string) {
if (!input.startsWith("@")) return input;
return input.slice(1);
}

Kysely Dialect for @std/sqlite

Caveats

It doesn't support transactions, there's no real way to do them on top of @std/sqlite AFAICT.

Usage

Create valimport { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect"; import { Kysely } from "npm:kysely"; const db = new Kysely({ dialect: new VtDialect(), });

Demo

See @easrng/kyselyVtDemo, which uses this along with @easrng/kyselyVtTypes to generate schema types.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import { sqlite } from "https://esm.town/v/std/sqlite";
import * as kysely from "npm:kysely@^0.27.3";
export class VtDialect implements kysely.Dialect {
createAdapter(): kysely.DialectAdapter {
return new kysely.SqliteAdapter();
}
createDriver(): kysely.Driver {
return new VtDriver();
}
createIntrospector(db: kysely.Kysely<any>): kysely.DatabaseIntrospector {
return new kysely.SqliteIntrospector(db);
}
createQueryCompiler(): kysely.QueryCompiler {
return new kysely.SqliteQueryCompiler();
}
}
export class VtDriver implements kysely.Driver {
async init(): Promise<void> {
}
async acquireConnection(): Promise<VtConnection> {
return new VtConnection();
}
async beginTransaction(
connection: VtConnection,
_settings: kysely.TransactionSettings,
): Promise<void> {
throw new Error("val.town does not support transactions");
}
async commitTransaction(connection: VtConnection): Promise<void> {
throw new Error("val.town does not support transactions");
}
async rollbackTransaction(connection: VtConnection): Promise<void> {
throw new Error("val.town does not support transactions");
}
async releaseConnection(connection: VtConnection): Promise<void> {
}
async destroy(): Promise<void> {
}
}
export class VtConnection implements kysely.DatabaseConnection {
async executeQuery<R>(compiledQuery: kysely.CompiledQuery): Promise<kysely.QueryResult<R>> {
const result = await sqlite.execute({
sql: compiledQuery.sql,
args: compiledQuery.parameters as any,
});
return {
numAffectedRows: BigInt(result.rowsAffected),
rows: result.rows.map(row => Object.fromEntries(row.map((value, i) => [result.columns[i], value]))) as R[],
};
}
async *streamQuery<R>(
_compiledQuery: kysely.CompiledQuery,
_chunkSize: number,
): AsyncIterableIterator<kysely.QueryResult<R>> {
throw new Error("val.town does not support streaming yet");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// SPDX-License-Identifier: 0BSD
import ky from "npm:ky";
import * as v from "npm:valibot";
export { HTTPError } from "npm:ky";
const PositiveIntegerSchema = v.number([v.integer(), v.minValue(0)]);
const ValSchema = v.transform(
v.object({
initialData: v.object({
id: v.string([v.uuid()]),
user: v.object({
handle: v.string(),
}),
name: v.string(),
code: v.string(),
version: PositiveIntegerSchema,
runEndAt: v.nullish(v.coerce(v.date(), (d) => new Date(d))),
readme: v.nullish(v.string()),
likeCount: PositiveIntegerSchema,
referenceCount: PositiveIntegerSchema,
commentCount: PositiveIntegerSchema,
forkCount: PositiveIntegerSchema,
prCount: PositiveIntegerSchema,
forkedVal: v.nullish(v.unknown()),
}),
}),
(input) => input.initialData,
);
const PageSchema = v.object({
page: PositiveIntegerSchema,
hasNext: v.boolean(),
vals: v.array(ValSchema),
});
export async function fetchNewestVals({ page = 0 } = {}) {
const url = new URL("https://www.val.town/newest");
url.searchParams.set("_data", "routes/_app.newest");
if (page) url.searchParams.set("page", `${page}`);
const resp = await ky.get(url).json();
return v.parse(PageSchema, resp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// SPDX-License-Identifier: 0BSD
import { API_URL } from "https://esm.town/v/std/API_URL?v=5";
import ky from "npm:ky";
import * as v from "npm:valibot";
export { HTTPError } from "npm:ky";
const PositiveIntegerSchema = v.number([v.integer(), v.minValue(0)]);
const ValSchema = v.object({
id: v.string([v.uuid()]),
author: v.object({
id: v.string([v.uuid()]),
username: v.string(),
}),
name: v.string(),
code: v.string(),
version: PositiveIntegerSchema,
runEndAt: v.nullish(v.coerce(v.date(), (d) => new Date(d))),
createdAt: v.coerce(v.date(), (d) => new Date(d)),
readme: v.nullish(v.string()),
likeCount: PositiveIntegerSchema,
referenceCount: PositiveIntegerSchema,
});
export async function fetchVal(author: string, name: string) {
const prefixUrl = new URL("/v1/alias", API_URL);
const resp = await ky.get(`${author}/${name}`, { prefixUrl }).json();
return v.parse(ValSchema, resp);
}

Val readme source viewer

ℹ️ As expected, I'm late to the party 😅 so go ahead and check out @pomdtr's wonderful @pomdtr/cdn val:
https://www.val.town/v/pomdtr/cdn#fetching-the-val-readme

Usage

https://vladimyr-mdviewer.web.val.run/v/<author>/<val>

Bookmarklet: vladimyr/bookmarkletMdViewer

Example

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SPDX-License-Identifier: 0BSD
import { fetchVal } from "https://esm.town/v/vladimyr/fetchVal";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { toHonoHandler } from "https://esm.town/v/vladimyr/toHonoHandler";
import { Hono } from "npm:hono";
import ky from "npm:ky";
const router = new Hono();
router.get("/", toHonoHandler(serveReadme(import.meta.url)));
router.get("/v/:author/:name", async (c) => {
const { author, name } = c.req.param();
const query = c.req.query();
const { readme } = await fetchVal(author, name);
// @see: https://datatracker.ietf.org/doc/html/rfc7763
c.header("content-type", "text/markdown; charset=UTF-8; variant=GFM");
return c.body(readme);
});
export default router.fetch;