@cloud-cli/d0 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +2 -1
- package/README.md +10 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +32 -19
- package/package.json +1 -1
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -32,9 +32,16 @@ import db from 'https://db.example.com/index.mjs';
|
|
|
32
32
|
const user = await db.query('SELECT * FROM user WHERE id = ?', [123]);
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Server address
|
|
36
|
+
|
|
37
|
+
If `BASE_DOMAIN` is set, the server will be available at `https://db-name.BASE_DOMAIN/` with a multi-database support, where `db-name` is the name of the database file without the `.sqlite` extension. The database is selected by the `db-name` part of the URL, so you can have multiple databases on the same server.
|
|
38
|
+
|
|
39
|
+
Otherwise, it will be available at `http://localhost:PORT/` and serve a single database.
|
|
40
|
+
|
|
35
41
|
## Environment variables
|
|
36
42
|
|
|
37
|
-
| Variable | Description
|
|
43
|
+
| Variable | Description |
|
|
38
44
|
|-|-|
|
|
39
|
-
| PORT | HTTP port
|
|
40
|
-
|
|
|
45
|
+
| PORT | HTTP port |
|
|
46
|
+
| DATA_PATH | Path to a folder where the database files are stored |
|
|
47
|
+
| BASE_DOMAIN | Root domain to use in a multi-db server, e.g. `.example.com` |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { IncomingMessage, ServerResponse } from
|
|
2
|
-
import { Database } from
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { Database } from "better-sqlite3";
|
|
3
3
|
type Q = {
|
|
4
4
|
db: Database;
|
|
5
5
|
request: IncomingMessage;
|
|
6
6
|
response: ServerResponse;
|
|
7
7
|
args: Record<string, string>;
|
|
8
8
|
};
|
|
9
|
-
export declare function getDatabase(): Database;
|
|
9
|
+
export declare function getDatabase(file?: string): Database;
|
|
10
10
|
export declare function serve(): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
11
11
|
export declare function handleRequest(request: any, response: any, db: any): Promise<void>;
|
|
12
12
|
export declare function onQuery({ db, request, response }: Q): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,40 @@
|
|
|
1
|
-
import { createServer } from
|
|
2
|
-
import { readFile } from
|
|
3
|
-
import SQLite from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import SQLite from "better-sqlite3";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
const methods = ["all", "run", "get"];
|
|
6
|
+
const baseDomain = process.env.BASE_DOMAIN;
|
|
7
|
+
const dataPath = process.env.DATA_PATH || join(import.meta.dirname, "data");
|
|
8
|
+
export function getDatabase(file = "db.sqlite3") {
|
|
9
|
+
const fullPath = join(dataPath, file);
|
|
10
|
+
const db = new SQLite(fullPath);
|
|
11
|
+
db.pragma("journal_mode = WAL");
|
|
8
12
|
return db;
|
|
9
13
|
}
|
|
10
14
|
export function serve() {
|
|
11
15
|
const db = getDatabase();
|
|
12
|
-
const server = createServer((req, res) =>
|
|
16
|
+
const server = createServer((req, res) => {
|
|
17
|
+
if (baseDomain) {
|
|
18
|
+
const hostname = String(req.headers["x-forwarded-for"] || "");
|
|
19
|
+
const subdomain = hostname.replace(baseDomain, "").replace(".", "");
|
|
20
|
+
if (subdomain) {
|
|
21
|
+
return handleRequest(req, res, getDatabase(subdomain + ".sqlite3"));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
handleRequest(req, res, db);
|
|
25
|
+
});
|
|
13
26
|
server.listen(process.env.PORT);
|
|
14
27
|
return server;
|
|
15
28
|
}
|
|
16
29
|
export function handleRequest(request, response, db) {
|
|
17
|
-
const url = new URL(request.url,
|
|
30
|
+
const url = new URL(request.url, "http://localhost");
|
|
18
31
|
const route = `${request.method} ${url.pathname}`.trim();
|
|
19
32
|
const args = Object.fromEntries(url.searchParams.entries());
|
|
20
33
|
const q = { db, request, response, args };
|
|
21
34
|
switch (route) {
|
|
22
|
-
case
|
|
35
|
+
case "GET /index.mjs":
|
|
23
36
|
return onEsModule(q);
|
|
24
|
-
case
|
|
37
|
+
case "POST /query":
|
|
25
38
|
return onQuery(q);
|
|
26
39
|
default:
|
|
27
40
|
response.writeHead(404).end();
|
|
@@ -34,12 +47,12 @@ export async function onQuery({ db, request, response }) {
|
|
|
34
47
|
return;
|
|
35
48
|
}
|
|
36
49
|
try {
|
|
37
|
-
const { s =
|
|
50
|
+
const { s = "", d, m = "run" } = JSON.parse(query.toString("utf-8"));
|
|
38
51
|
if (!s.trim()) {
|
|
39
|
-
throw new Error(
|
|
52
|
+
throw new Error("Invalid statement.");
|
|
40
53
|
}
|
|
41
54
|
if (!methods.includes(m)) {
|
|
42
|
-
throw new Error(
|
|
55
|
+
throw new Error("Invalid method. Must be one of " + methods.join(", "));
|
|
43
56
|
}
|
|
44
57
|
const runner = db.prepare(s);
|
|
45
58
|
const result = d ? runner[m](d) : runner[m]();
|
|
@@ -53,17 +66,17 @@ export async function onQuery({ db, request, response }) {
|
|
|
53
66
|
let file;
|
|
54
67
|
async function getFile() {
|
|
55
68
|
if (!file) {
|
|
56
|
-
file = await readFile(
|
|
69
|
+
file = await readFile("./client.mjs", "utf8");
|
|
57
70
|
}
|
|
58
71
|
return file;
|
|
59
72
|
}
|
|
60
73
|
async function onEsModule({ request, response }) {
|
|
61
|
-
const hostname = request.headers[
|
|
74
|
+
const hostname = request.headers["x-forwarded-for"];
|
|
62
75
|
const code = await getFile();
|
|
63
76
|
response
|
|
64
77
|
.writeHead(200, {
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
"Content-Type": "text/javascript",
|
|
79
|
+
"Access-Control-Allow-Origin": "*",
|
|
67
80
|
})
|
|
68
|
-
.end(code.replace(
|
|
81
|
+
.end(code.replace("__API_URL__", hostname));
|
|
69
82
|
}
|