@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 CHANGED
@@ -1,4 +1,5 @@
1
1
  FROM ghcr.io/cloud-cli/node:latest
2
+ USER root
2
3
  COPY . /home/app
3
- RUN cd /home/app && npm i && npm run build && rm -r src/
4
4
  ENV NODE_ENV=production
5
+ RUN cd /home/app && npm i && npm run build && rm -r src/
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
- | SQLITE_DB_PATH | Path to file where the database files are stored |
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 'node:http';
2
- import { Database } from 'better-sqlite3';
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 'node:http';
2
- import { readFile } from 'node:fs/promises';
3
- import SQLite from 'better-sqlite3';
4
- const methods = ['all', 'run', 'get'];
5
- export function getDatabase() {
6
- const db = new SQLite(process.env.SQLITE_DB_PATH || './db.sqlite3');
7
- db.pragma('journal_mode = WAL');
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) => handleRequest(req, res, db));
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, 'http://localhost');
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 'GET /index.mjs':
35
+ case "GET /index.mjs":
23
36
  return onEsModule(q);
24
- case 'POST /query':
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 = '', d, m = 'run' } = JSON.parse(query.toString('utf-8'));
50
+ const { s = "", d, m = "run" } = JSON.parse(query.toString("utf-8"));
38
51
  if (!s.trim()) {
39
- throw new Error('Invalid statement.');
52
+ throw new Error("Invalid statement.");
40
53
  }
41
54
  if (!methods.includes(m)) {
42
- throw new Error('Invalid method. Must be one of ' + methods.join(', '));
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('./client.mjs', 'utf8');
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['x-forwarded-for'];
74
+ const hostname = request.headers["x-forwarded-for"];
62
75
  const code = await getFile();
63
76
  response
64
77
  .writeHead(200, {
65
- 'Content-Type': 'text/javascript',
66
- 'Access-Control-Allow-Origin': '*',
78
+ "Content-Type": "text/javascript",
79
+ "Access-Control-Allow-Origin": "*",
67
80
  })
68
- .end(code.replace('__API_URL__', hostname));
81
+ .end(code.replace("__API_URL__", hostname));
69
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-cli/d0",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",