Complete Astro migration - PDPA compliant website

- Migrated all pages from Next.js to Astro
- Added PDPA-compliant Privacy Policy (Thai)
- Added PDPA-compliant Terms & Conditions (Thai)
- Added Cookie Policy with disclosure (Thai)
- Implemented cookie consent banner (client-side)
- Integrated Umami Analytics placeholder
- Blog system with 3 posts
- Optimized Docker configuration for production
- Static site build (184KB, 11 pages)
- Ready for Easypanel deployment

Backup: /Users/kunthawatgreethong/Gitea/dealplustech-backup-nextjs-20260309.tar.gz
This commit is contained in:
Kunthawat Greethong
2026-03-09 18:28:01 +07:00
parent 668f69048f
commit 6402d885f9
6183 changed files with 463899 additions and 1913 deletions

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LibsqlBatchError = exports.LibsqlError = void 0;
/** Error thrown by the client. */
class LibsqlError extends Error {
/** Machine-readable error code. */
code;
/** Extended error code with more specific information (e.g., SQLITE_CONSTRAINT_PRIMARYKEY). */
extendedCode;
/** Raw numeric error code */
rawCode;
constructor(message, code, extendedCode, rawCode, cause) {
if (code !== undefined) {
message = `${code}: ${message}`;
}
super(message, { cause });
this.code = code;
this.extendedCode = extendedCode;
this.rawCode = rawCode;
this.name = "LibsqlError";
}
}
exports.LibsqlError = LibsqlError;
/** Error thrown by the client during batch operations. */
class LibsqlBatchError extends LibsqlError {
/** The zero-based index of the statement that failed in the batch. */
statementIndex;
constructor(message, statementIndex, code, extendedCode, rawCode, cause) {
super(message, code, extendedCode, rawCode, cause);
this.statementIndex = statementIndex;
this.name = "LibsqlBatchError";
}
}
exports.LibsqlBatchError = LibsqlBatchError;

View File

@@ -0,0 +1,143 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.expandConfig = exports.isInMemoryConfig = void 0;
const api_js_1 = require("./api.js");
const uri_js_1 = require("./uri.js");
const util_js_1 = require("./util.js");
const inMemoryMode = ":memory:";
function isInMemoryConfig(config) {
return (config.scheme === "file" &&
(config.path === ":memory:" || config.path.startsWith(":memory:?")));
}
exports.isInMemoryConfig = isInMemoryConfig;
function expandConfig(config, preferHttp) {
if (typeof config !== "object") {
// produce a reasonable error message in the common case where users type
// `createClient("libsql://...")` instead of `createClient({url: "libsql://..."})`
throw new TypeError(`Expected client configuration as object, got ${typeof config}`);
}
let { url, authToken, tls, intMode, concurrency } = config;
// fill simple defaults right here
concurrency = Math.max(0, concurrency || 20);
intMode ??= "number";
let connectionQueryParams = []; // recognized query parameters which we sanitize through white list of valid key-value pairs
// convert plain :memory: url to URI format to make logic more uniform
if (url === inMemoryMode) {
url = "file::memory:";
}
// parse url parameters first and override config with update values
const uri = (0, uri_js_1.parseUri)(url);
const originalUriScheme = uri.scheme.toLowerCase();
const isInMemoryMode = originalUriScheme === "file" &&
uri.path === inMemoryMode &&
uri.authority === undefined;
let queryParamsDef;
if (isInMemoryMode) {
queryParamsDef = {
cache: {
values: ["shared", "private"],
update: (key, value) => connectionQueryParams.push(`${key}=${value}`),
},
};
}
else {
queryParamsDef = {
tls: {
values: ["0", "1"],
update: (_, value) => (tls = value === "1"),
},
authToken: {
update: (_, value) => (authToken = value),
},
};
}
for (const { key, value } of uri.query?.pairs ?? []) {
if (!Object.hasOwn(queryParamsDef, key)) {
throw new api_js_1.LibsqlError(`Unsupported URL query parameter ${JSON.stringify(key)}`, "URL_PARAM_NOT_SUPPORTED");
}
const queryParamDef = queryParamsDef[key];
if (queryParamDef.values !== undefined &&
!queryParamDef.values.includes(value)) {
throw new api_js_1.LibsqlError(`Unknown value for the "${key}" query argument: ${JSON.stringify(value)}. Supported values are: [${queryParamDef.values.map((x) => '"' + x + '"').join(", ")}]`, "URL_INVALID");
}
if (queryParamDef.update !== undefined) {
queryParamDef?.update(key, value);
}
}
// fill complex defaults & validate config
const connectionQueryParamsString = connectionQueryParams.length === 0
? ""
: `?${connectionQueryParams.join("&")}`;
const path = uri.path + connectionQueryParamsString;
let scheme;
if (originalUriScheme === "libsql") {
if (tls === false) {
if (uri.authority?.port === undefined) {
throw new api_js_1.LibsqlError('A "libsql:" URL with ?tls=0 must specify an explicit port', "URL_INVALID");
}
scheme = preferHttp ? "http" : "ws";
}
else {
scheme = preferHttp ? "https" : "wss";
}
}
else {
scheme = originalUriScheme;
}
if (scheme === "http" || scheme === "ws") {
tls ??= false;
}
else {
tls ??= true;
}
if (scheme !== "http" &&
scheme !== "ws" &&
scheme !== "https" &&
scheme !== "wss" &&
scheme !== "file") {
throw new api_js_1.LibsqlError('The client supports only "libsql:", "wss:", "ws:", "https:", "http:" and "file:" URLs, ' +
`got ${JSON.stringify(uri.scheme + ":")}. ` +
`For more information, please read ${util_js_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
}
if (intMode !== "number" && intMode !== "bigint" && intMode !== "string") {
throw new TypeError(`Invalid value for intMode, expected "number", "bigint" or "string", got ${JSON.stringify(intMode)}`);
}
if (uri.fragment !== undefined) {
throw new api_js_1.LibsqlError(`URL fragments are not supported: ${JSON.stringify("#" + uri.fragment)}`, "URL_INVALID");
}
if (isInMemoryMode) {
return {
scheme: "file",
tls: false,
path,
intMode,
concurrency,
syncUrl: config.syncUrl,
syncInterval: config.syncInterval,
readYourWrites: config.readYourWrites,
offline: config.offline,
fetch: config.fetch,
authToken: undefined,
encryptionKey: undefined,
remoteEncryptionKey: undefined,
authority: undefined,
};
}
return {
scheme,
tls,
authority: uri.authority,
path,
authToken,
intMode,
concurrency,
encryptionKey: config.encryptionKey,
remoteEncryptionKey: config.remoteEncryptionKey,
syncUrl: config.syncUrl,
syncInterval: config.syncInterval,
readYourWrites: config.readYourWrites,
offline: config.offline,
fetch: config.fetch,
};
}
exports.expandConfig = expandConfig;

View File

@@ -0,0 +1,3 @@
{
"type": "commonjs"
}

View File

@@ -0,0 +1,125 @@
"use strict";
// URI parser based on RFC 3986
// We can't use the standard `URL` object, because we want to support relative `file:` URLs like
// `file:relative/path/database.db`, which are not correct according to RFC 8089, which standardizes the
// `file` scheme.
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeBaseUrl = exports.parseUri = void 0;
const api_js_1 = require("./api.js");
function parseUri(text) {
const match = URI_RE.exec(text);
if (match === null) {
throw new api_js_1.LibsqlError(`The URL '${text}' is not in a valid format`, "URL_INVALID");
}
const groups = match.groups;
const scheme = groups["scheme"];
const authority = groups["authority"] !== undefined
? parseAuthority(groups["authority"])
: undefined;
const path = percentDecode(groups["path"]);
const query = groups["query"] !== undefined ? parseQuery(groups["query"]) : undefined;
const fragment = groups["fragment"] !== undefined
? percentDecode(groups["fragment"])
: undefined;
return { scheme, authority, path, query, fragment };
}
exports.parseUri = parseUri;
const URI_RE = (() => {
const SCHEME = "(?<scheme>[A-Za-z][A-Za-z.+-]*)";
const AUTHORITY = "(?<authority>[^/?#]*)";
const PATH = "(?<path>[^?#]*)";
const QUERY = "(?<query>[^#]*)";
const FRAGMENT = "(?<fragment>.*)";
return new RegExp(`^${SCHEME}:(//${AUTHORITY})?${PATH}(\\?${QUERY})?(#${FRAGMENT})?$`, "su");
})();
function parseAuthority(text) {
const match = AUTHORITY_RE.exec(text);
if (match === null) {
throw new api_js_1.LibsqlError("The authority part of the URL is not in a valid format", "URL_INVALID");
}
const groups = match.groups;
const host = percentDecode(groups["host_br"] ?? groups["host"]);
const port = groups["port"] ? parseInt(groups["port"], 10) : undefined;
const userinfo = groups["username"] !== undefined
? {
username: percentDecode(groups["username"]),
password: groups["password"] !== undefined
? percentDecode(groups["password"])
: undefined,
}
: undefined;
return { host, port, userinfo };
}
const AUTHORITY_RE = (() => {
return new RegExp(`^((?<username>[^:]*)(:(?<password>.*))?@)?((?<host>[^:\\[\\]]*)|(\\[(?<host_br>[^\\[\\]]*)\\]))(:(?<port>[0-9]*))?$`, "su");
})();
// Query string is parsed as application/x-www-form-urlencoded according to the Web URL standard:
// https://url.spec.whatwg.org/#urlencoded-parsing
function parseQuery(text) {
const sequences = text.split("&");
const pairs = [];
for (const sequence of sequences) {
if (sequence === "") {
continue;
}
let key;
let value;
const splitIdx = sequence.indexOf("=");
if (splitIdx < 0) {
key = sequence;
value = "";
}
else {
key = sequence.substring(0, splitIdx);
value = sequence.substring(splitIdx + 1);
}
pairs.push({
key: percentDecode(key.replaceAll("+", " ")),
value: percentDecode(value.replaceAll("+", " ")),
});
}
return { pairs };
}
function percentDecode(text) {
try {
return decodeURIComponent(text);
}
catch (e) {
if (e instanceof URIError) {
throw new api_js_1.LibsqlError(`URL component has invalid percent encoding: ${e}`, "URL_INVALID", undefined, undefined, e);
}
throw e;
}
}
function encodeBaseUrl(scheme, authority, path) {
if (authority === undefined) {
throw new api_js_1.LibsqlError(`URL with scheme ${JSON.stringify(scheme + ":")} requires authority (the "//" part)`, "URL_INVALID");
}
const schemeText = `${scheme}:`;
const hostText = encodeHost(authority.host);
const portText = encodePort(authority.port);
const userinfoText = encodeUserinfo(authority.userinfo);
const authorityText = `//${userinfoText}${hostText}${portText}`;
let pathText = path.split("/").map(encodeURIComponent).join("/");
if (pathText !== "" && !pathText.startsWith("/")) {
pathText = "/" + pathText;
}
return new URL(`${schemeText}${authorityText}${pathText}`);
}
exports.encodeBaseUrl = encodeBaseUrl;
function encodeHost(host) {
return host.includes(":") ? `[${encodeURI(host)}]` : encodeURI(host);
}
function encodePort(port) {
return port !== undefined ? `:${port}` : "";
}
function encodeUserinfo(userinfo) {
if (userinfo === undefined) {
return "";
}
const usernameText = encodeURIComponent(userinfo.username);
const passwordText = userinfo.password !== undefined
? `:${encodeURIComponent(userinfo.password)}`
: "";
return `${usernameText}${passwordText}@`;
}

View File

@@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResultSetImpl = exports.transactionModeToBegin = exports.supportedUrlLink = void 0;
const js_base64_1 = require("js-base64");
exports.supportedUrlLink = "https://github.com/libsql/libsql-client-ts#supported-urls";
function transactionModeToBegin(mode) {
if (mode === "write") {
return "BEGIN IMMEDIATE";
}
else if (mode === "read") {
return "BEGIN TRANSACTION READONLY";
}
else if (mode === "deferred") {
return "BEGIN DEFERRED";
}
else {
throw RangeError('Unknown transaction mode, supported values are "write", "read" and "deferred"');
}
}
exports.transactionModeToBegin = transactionModeToBegin;
class ResultSetImpl {
columns;
columnTypes;
rows;
rowsAffected;
lastInsertRowid;
constructor(columns, columnTypes, rows, rowsAffected, lastInsertRowid) {
this.columns = columns;
this.columnTypes = columnTypes;
this.rows = rows;
this.rowsAffected = rowsAffected;
this.lastInsertRowid = lastInsertRowid;
}
toJSON() {
return {
columns: this.columns,
columnTypes: this.columnTypes,
rows: this.rows.map(rowToJson),
rowsAffected: this.rowsAffected,
lastInsertRowid: this.lastInsertRowid !== undefined
? "" + this.lastInsertRowid
: null,
};
}
}
exports.ResultSetImpl = ResultSetImpl;
function rowToJson(row) {
return Array.prototype.map.call(row, valueToJson);
}
function valueToJson(value) {
if (typeof value === "bigint") {
return "" + value;
}
else if (value instanceof ArrayBuffer) {
return js_base64_1.Base64.fromUint8Array(new Uint8Array(value));
}
else {
return value;
}
}