easrng-kyselyvttypes.web.val.run
Readme

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.

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,
});
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
2
pomdtr avatar

Quick thought, you could protect your types behind a password.

You just need to implement bearer token authentication in the vals, and use the private module mechanism: https://www.val.town/settings/private-modules

easrng avatar

That was what I did initially but the editor doesn't respect the private module settings.

v54
April 1, 2024