@sfmc-bds/db-server 0.2.0-beta.0 → 0.2.0-beta.5

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/dist/env.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoBH,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,OAAO,IAAI,SAAS,CAyFnC"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,OAAO,IAAI,SAAS,CAyFnC"}
package/dist/env.js CHANGED
@@ -2,18 +2,14 @@ import {
2
2
  ensureCoreConfigs,
3
3
  loadEnsuredConfig,
4
4
  modulePath,
5
- resolveRuntimeRoot,
6
5
  DEFAULT_DB_CONFIG,
7
6
  DEFAULT_QQ_CONFIG
8
7
  } from "@sfmc-bds/sdk/node/config";
9
8
  import { isAbsolute, join, resolve } from "node:path";
10
- import { fileURLToPath } from "node:url";
11
9
  import { log } from "./lib/log.js";
12
- import { dirname } from "node:path";
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
10
+ import { PROJECT_ROOT as RESOLVED_ROOT } from "./project-root.js";
15
11
  function loadEnv() {
16
- const PROJECT_ROOT = resolveRuntimeRoot(resolve(__dirname, "..", ".."));
12
+ const PROJECT_ROOT = RESOLVED_ROOT;
17
13
  ensureCoreConfigs(PROJECT_ROOT, ["db_config", "qq_config", "permissions"]);
18
14
  const dbconfig = loadEnsuredConfig(
19
15
  PROJECT_ROOT,
package/dist/env.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/env.ts"],
4
- "sourcesContent": ["/**\n * env.ts \u2014 \u73AF\u5883\u914D\u7F6E\u52A0\u8F7D\n */\n\nimport {\n ensureCoreConfigs,\n loadEnsuredConfig,\n modulePath,\n resolveRuntimeRoot,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { log } from \"./lib/log.js\";\n\nimport { dirname } from \"node:path\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport interface EnvConfig {\n PROJECT_ROOT: string;\n PORT: number;\n HOST: string;\n DB_PATH: string;\n AUTH_TOKEN: string;\n // LLBot HTTP\n LLBOT_HOST: string;\n LLBOT_PORT: number;\n LLBOT_TOKEN: string;\n // QQ \u7FA4 / channel(\u4ECE qq_config.json \u900F\u51FA,\u7ED9 bridge / messages \u8DEF\u7531\u7528)\n QQ_GROUP_ID: string;\n QQ_BRIDGE_CHANNEL_ID: string;\n MODULES_DIR: string;\n MODULE_CATALOG_PATH: string;\n MODULE_LOCK_PATH: string;\n dbconfig: Record<string, unknown>;\n qqconfig: Record<string, unknown>;\n}\n\nexport function loadEnv(): EnvConfig {\n const PROJECT_ROOT = resolveRuntimeRoot(resolve(__dirname, \"..\", \"..\"));\n /* \u542F\u52A8\u65F6\u786E\u8BA4 db/qq/permissions \u5B58\u5728;\u4E0D\u5B58\u5728\u5C31\u5199\u5E26\u9ED8\u8BA4\u503C\u7684\u9AA8\u67B6\u3002\n * \u4E0D\u4F9D\u8D56 wizard:wizard \u53EA\u586B\u5B57\u6BB5,\u9AA8\u67B6\u7531\u670D\u52A1\u81EA\u5DF1 ensure\u3002 */\n ensureCoreConfigs(PROJECT_ROOT, [\"db_config\", \"qq_config\", \"permissions\"]);\n const dbconfig = loadEnsuredConfig(\n PROJECT_ROOT,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n );\n const qqconfig = loadEnsuredConfig(\n PROJECT_ROOT,\n \"qq_config.json\",\n \"qq_config\",\n { ...DEFAULT_QQ_CONFIG } as Record<string, unknown>\n );\n\n // \u2500\u2500 \u4F18\u5148\u7EA7:JSON > \u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF > \u9ED8\u8BA4\u503C \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const envBaseline = { ...process.env };\n\n for (const [k, v] of Object.entries(dbconfig)) {\n const envKey = k.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n process.env[envKey] = String(v);\n log.info(`db_config::${k} -> process.env.${envKey} = ${String(v)}`);\n }\n for (const [k, v] of Object.entries(qqconfig)) {\n const envKey = k.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n if (process.env[envKey] === undefined) {\n process.env[envKey] = String(v);\n log.info(`qq_config::${k} -> process.env.${envKey} = ${String(v)}`);\n }\n }\n\n // \u5DE5\u5177:JSON > envBaseline(\u539F process.env) > default\n // \u8BED\u4E49:JSON \u91CC\u6709\u8FD9\u4E2A\u952E(\u975E undefined / null)\u5C31\u7528 JSON;\u7A7A\u4E32\u30010\u3001false \u90FD\u7B97\"\u663E\u5F0F\u914D\u7F6E\"\n // \u53EA\u6709 JSON \u5B8C\u5168\u6CA1\u8FD9\u4E2A\u952E(\u6216\u8005\u663E\u5F0F null)\u624D fall through \u5230 env\n function pick<T>(jsonVal: T | undefined | null, envKey: string, fallback: T, source: string): T {\n if (jsonVal !== undefined && jsonVal !== null) {\n return jsonVal;\n }\n const fromEnv = envBaseline[envKey];\n if (fromEnv !== undefined && fromEnv !== \"\") {\n log.info(`${source} \u672A\u5728 JSON \u4E2D\u914D\u7F6E,\u4F7F\u7528\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF ${envKey} = ${fromEnv}`);\n return fromEnv as unknown as T;\n }\n return fallback;\n }\n\n const PORT = parseInt(String(pick(dbconfig[\"db_port\"] as number | undefined, \"DB_PORT\", 3001, \"db_port\")), 10);\n const HOST = \"127.0.0.1\";\n const DB_PATH_RAW = String(pick(dbconfig[\"dbDir\"] as string | undefined, \"DB_DIR\", \"data/sfmc_data.db\", \"dbDir\"));\n const DB_PATH = isAbsolute(DB_PATH_RAW) ? DB_PATH_RAW : resolve(PROJECT_ROOT, DB_PATH_RAW);\n const LLBOT_HOST = String(\n pick(qqconfig[\"llbot_host\"] as string | undefined, \"LLBOT_HOST\", \"127.0.0.1\", \"llbot_host\")\n );\n const LLBOT_PORT = parseInt(\n String(pick(qqconfig[\"llbot_port\"] as number | undefined, \"LLBOT_PORT\", 3004, \"llbot_port\")),\n 10\n );\n const LLBOT_TOKEN = String(pick(qqconfig[\"llbot_token\"] as string | undefined, \"LLBOT_TOKEN\", \"\", \"llbot_token\"));\n const QQ_GROUP_ID = String(pick(qqconfig[\"qq_group_id\"] as string | undefined, \"QQ_GROUP_ID\", \"\", \"qq_group_id\"));\n const QQ_BRIDGE_CHANNEL_ID = String(\n pick(qqconfig[\"bridge_channel_id\"] as string | undefined, \"BRIDGE_CHANNEL_ID\", \"\", \"bridge_channel_id\")\n );\n const AUTH_TOKEN = String(pick(dbconfig[\"http_auth\"] as string | undefined, \"HTTP_AUTH\", \"\", \"http_auth\"));\n const MODULES_DIR = dbconfig[\"modulesDir\"]\n ? resolve(PROJECT_ROOT, String(dbconfig[\"modulesDir\"]))\n : join(PROJECT_ROOT, \"modules\");\n const MODULE_CATALOG_PATH = modulePath(MODULES_DIR, \"catalog.json\");\n const MODULE_LOCK_PATH = modulePath(MODULES_DIR, \"module-lock.json\");\n\n return {\n PROJECT_ROOT,\n PORT,\n HOST,\n DB_PATH,\n AUTH_TOKEN,\n LLBOT_HOST,\n LLBOT_PORT,\n LLBOT_TOKEN,\n QQ_GROUP_ID,\n QQ_BRIDGE_CHANNEL_ID,\n MODULES_DIR,\n MODULE_CATALOG_PATH,\n MODULE_LOCK_PATH,\n dbconfig,\n qqconfig,\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * env.ts \u2014 \u73AF\u5883\u914D\u7F6E\u52A0\u8F7D\n */\n\nimport {\n ensureCoreConfigs,\n loadEnsuredConfig,\n modulePath,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { isAbsolute, join, resolve } from \"node:path\";\n\nimport { log } from \"./lib/log.js\";\nimport { PROJECT_ROOT as RESOLVED_ROOT } from \"./project-root.js\";\n\n\nexport interface EnvConfig {\n PROJECT_ROOT: string;\n PORT: number;\n HOST: string;\n DB_PATH: string;\n AUTH_TOKEN: string;\n // LLBot HTTP\n LLBOT_HOST: string;\n LLBOT_PORT: number;\n LLBOT_TOKEN: string;\n // QQ \u7FA4 / channel(\u4ECE qq_config.json \u900F\u51FA,\u7ED9 bridge / messages \u8DEF\u7531\u7528)\n QQ_GROUP_ID: string;\n QQ_BRIDGE_CHANNEL_ID: string;\n MODULES_DIR: string;\n MODULE_CATALOG_PATH: string;\n MODULE_LOCK_PATH: string;\n dbconfig: Record<string, unknown>;\n qqconfig: Record<string, unknown>;\n}\n\nexport function loadEnv(): EnvConfig {\n const PROJECT_ROOT = RESOLVED_ROOT;\n /* \u542F\u52A8\u65F6\u786E\u8BA4 db/qq/permissions \u5B58\u5728;\u4E0D\u5B58\u5728\u5C31\u5199\u5E26\u9ED8\u8BA4\u503C\u7684\u9AA8\u67B6\u3002\n * \u4E0D\u4F9D\u8D56 wizard:wizard \u53EA\u586B\u5B57\u6BB5,\u9AA8\u67B6\u7531\u670D\u52A1\u81EA\u5DF1 ensure\u3002 */\n ensureCoreConfigs(PROJECT_ROOT, [\"db_config\", \"qq_config\", \"permissions\"]);\n const dbconfig = loadEnsuredConfig(\n PROJECT_ROOT,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n );\n const qqconfig = loadEnsuredConfig(\n PROJECT_ROOT,\n \"qq_config.json\",\n \"qq_config\",\n { ...DEFAULT_QQ_CONFIG } as Record<string, unknown>\n );\n\n // \u2500\u2500 \u4F18\u5148\u7EA7:JSON > \u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF > \u9ED8\u8BA4\u503C \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const envBaseline = { ...process.env };\n\n for (const [k, v] of Object.entries(dbconfig)) {\n const envKey = k.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n process.env[envKey] = String(v);\n log.info(`db_config::${k} -> process.env.${envKey} = ${String(v)}`);\n }\n for (const [k, v] of Object.entries(qqconfig)) {\n const envKey = k.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n if (process.env[envKey] === undefined) {\n process.env[envKey] = String(v);\n log.info(`qq_config::${k} -> process.env.${envKey} = ${String(v)}`);\n }\n }\n\n // \u5DE5\u5177:JSON > envBaseline(\u539F process.env) > default\n // \u8BED\u4E49:JSON \u91CC\u6709\u8FD9\u4E2A\u952E(\u975E undefined / null)\u5C31\u7528 JSON;\u7A7A\u4E32\u30010\u3001false \u90FD\u7B97\"\u663E\u5F0F\u914D\u7F6E\"\n // \u53EA\u6709 JSON \u5B8C\u5168\u6CA1\u8FD9\u4E2A\u952E(\u6216\u8005\u663E\u5F0F null)\u624D fall through \u5230 env\n function pick<T>(jsonVal: T | undefined | null, envKey: string, fallback: T, source: string): T {\n if (jsonVal !== undefined && jsonVal !== null) {\n return jsonVal;\n }\n const fromEnv = envBaseline[envKey];\n if (fromEnv !== undefined && fromEnv !== \"\") {\n log.info(`${source} \u672A\u5728 JSON \u4E2D\u914D\u7F6E,\u4F7F\u7528\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF ${envKey} = ${fromEnv}`);\n return fromEnv as unknown as T;\n }\n return fallback;\n }\n\n const PORT = parseInt(String(pick(dbconfig[\"db_port\"] as number | undefined, \"DB_PORT\", 3001, \"db_port\")), 10);\n const HOST = \"127.0.0.1\";\n const DB_PATH_RAW = String(pick(dbconfig[\"dbDir\"] as string | undefined, \"DB_DIR\", \"data/sfmc_data.db\", \"dbDir\"));\n const DB_PATH = isAbsolute(DB_PATH_RAW) ? DB_PATH_RAW : resolve(PROJECT_ROOT, DB_PATH_RAW);\n const LLBOT_HOST = String(\n pick(qqconfig[\"llbot_host\"] as string | undefined, \"LLBOT_HOST\", \"127.0.0.1\", \"llbot_host\")\n );\n const LLBOT_PORT = parseInt(\n String(pick(qqconfig[\"llbot_port\"] as number | undefined, \"LLBOT_PORT\", 3004, \"llbot_port\")),\n 10\n );\n const LLBOT_TOKEN = String(pick(qqconfig[\"llbot_token\"] as string | undefined, \"LLBOT_TOKEN\", \"\", \"llbot_token\"));\n const QQ_GROUP_ID = String(pick(qqconfig[\"qq_group_id\"] as string | undefined, \"QQ_GROUP_ID\", \"\", \"qq_group_id\"));\n const QQ_BRIDGE_CHANNEL_ID = String(\n pick(qqconfig[\"bridge_channel_id\"] as string | undefined, \"BRIDGE_CHANNEL_ID\", \"\", \"bridge_channel_id\")\n );\n const AUTH_TOKEN = String(pick(dbconfig[\"http_auth\"] as string | undefined, \"HTTP_AUTH\", \"\", \"http_auth\"));\n const MODULES_DIR = dbconfig[\"modulesDir\"]\n ? resolve(PROJECT_ROOT, String(dbconfig[\"modulesDir\"]))\n : join(PROJECT_ROOT, \"modules\");\n const MODULE_CATALOG_PATH = modulePath(MODULES_DIR, \"catalog.json\");\n const MODULE_LOCK_PATH = modulePath(MODULES_DIR, \"module-lock.json\");\n\n return {\n PROJECT_ROOT,\n PORT,\n HOST,\n DB_PATH,\n AUTH_TOKEN,\n LLBOT_HOST,\n LLBOT_PORT,\n LLBOT_TOKEN,\n QQ_GROUP_ID,\n QQ_BRIDGE_CHANNEL_ID,\n MODULES_DIR,\n MODULE_CATALOG_PATH,\n MODULE_LOCK_PATH,\n dbconfig,\n qqconfig,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,eAAO,MAAM,GAAG,gDAGd,CAAC"}
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,eAAO,MAAM,GAAG,gDAGd,CAAC"}
package/dist/lib/log.js CHANGED
@@ -1,13 +1,10 @@
1
1
  import { createNodeServiceLogger } from "@sfmc-bds/sdk/logs";
2
- import { logFile, resolveRuntimeRoot } from "@sfmc-bds/sdk/node/config";
3
- import { dirname, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- const ROOT = resolveRuntimeRoot(resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", ".."));
2
+ import { logFile } from "@sfmc-bds/sdk/node/config";
3
+ import { PROJECT_ROOT } from "../project-root.js";
6
4
  const log = createNodeServiceLogger({
7
5
  source: "db",
8
- logPath: logFile(ROOT, "db")
6
+ logPath: logFile(PROJECT_ROOT, "db")
9
7
  });
10
- process.on("exit", () => log.close());
11
8
  export {
12
9
  log
13
10
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/log.ts"],
4
- "sourcesContent": ["/**\n * log.ts \u2014 db-server \u7EDF\u4E00\u65E5\u5FD7\u5B9E\u4F8B\n *\n * stdout bare + \u843D\u76D8 `<SFMC_ROOT>/.sfmc/logs/db.log`\u3002\n * bare: \u53EA\u8F93\u51FA\u7EAF text,\u7531 sfmc \u6355\u83B7\u540E\u7EDF\u4E00\u52A0\u524D\u7F00;error \u8D70 stderr\u3002\n */\n\nimport { createNodeServiceLogger } from \"@sfmc-bds/sdk/logs\";\nimport { logFile, resolveRuntimeRoot } from \"@sfmc-bds/sdk/node/config\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/** src/lib \u2192 \u4ED3\u6839(\u4E0E env.ts \u7684 src \u4E0A\u6EAF\u5DEE\u4E00\u5C42) */\nconst ROOT = resolveRuntimeRoot(resolve(dirname(fileURLToPath(import.meta.url)), \"..\", \"..\", \"..\"));\n\nexport const log = createNodeServiceLogger({\n source: \"db\",\n logPath: logFile(ROOT, \"db\"),\n});\n\nprocess.on(\"exit\", () => log.close());\n"],
5
- "mappings": "AAOA,SAAS,+BAA+B;AACxC,SAAS,SAAS,0BAA0B;AAC5C,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;AAG9B,MAAM,OAAO,mBAAmB,QAAQ,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,MAAM,MAAM,IAAI,CAAC;AAE3F,MAAM,MAAM,wBAAwB;AAAA,EACzC,QAAQ;AAAA,EACR,SAAS,QAAQ,MAAM,IAAI;AAC7B,CAAC;AAED,QAAQ,GAAG,QAAQ,MAAM,IAAI,MAAM,CAAC;",
4
+ "sourcesContent": ["/**\n * log.ts \u2014 db-server \u7EDF\u4E00\u65E5\u5FD7\u5B9E\u4F8B\n *\n * stdout bare + \u843D\u76D8 `<SFMC_ROOT>/.sfmc/logs/db.log`\u3002\n * bare: \u53EA\u8F93\u51FA\u7EAF text,\u7531 sfmc \u6355\u83B7\u540E\u7EDF\u4E00\u52A0\u524D\u7F00;error \u8D70 stderr\u3002\n */\n\nimport { createNodeServiceLogger } from \"@sfmc-bds/sdk/logs\";\nimport { logFile } from \"@sfmc-bds/sdk/node/config\";\nimport { PROJECT_ROOT } from \"../project-root.js\";\n\nexport const log = createNodeServiceLogger({\n source: \"db\",\n logPath: logFile(PROJECT_ROOT, \"db\"),\n});\n"],
5
+ "mappings": "AAOA,SAAS,+BAA+B;AACxC,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAEtB,MAAM,MAAM,wBAAwB;AAAA,EACzC,QAAQ;AAAA,EACR,SAAS,QAAQ,cAAc,IAAI;AACrC,CAAC;",
6
6
  "names": []
7
7
  }
@@ -37,7 +37,7 @@ function buildModuleAuth(opts) {
37
37
  if (process.env.SFMC_LOG_MODULE_TOKEN === "1") {
38
38
  log.info("[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):");
39
39
  for (const [id, t] of Object.entries(tokens)) {
40
- console.log(` ${id} = ${t}`);
40
+ log.info(` ${id} = ${t}`);
41
41
  }
42
42
  } else {
43
43
  const lines = Object.entries(tokens).map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`).join("\n");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/module-auth.ts"],
4
- "sourcesContent": ["/**\n * module-auth.ts \u2014 \u6A21\u5757\u8EAB\u4EFD\u7684 HMAC token \u6D3E\u751F\u4E0E\u6821\u9A8C\n *\n * \u4E24\u5957\u5E76\u5B58:\n * - `env.AUTH_TOKEN` (config db_config.json http_auth):sfmc \u7BA1\u63A7 / \u5E73\u53F0\u5185\u90E8\u7528\n * - `moduleTokens[moduleId]`:db-server \u7ED9\u6BCF\u4E2A enabled \u6A21\u5757\u5728\u542F\u52A8\u65F6\u6D3E\u751F,\n * \u5199\u5230\u300C\u4E0E\u6570\u636E\u5E93\u540C\u76EE\u5F55\u300D\u7684 module-tokens.json\uFF08\u8DDF db_config.dbDir \u8D70\uFF0C\u52FF\u5199\u6B7B ROOT/data\uFF09,\n * SAPI \u7ECF loopback API \u6CE8\u5165 setDbModuleContext\u3002\n *\n * \u6D3E\u751F\u516C\u5F0F:\n * module_token = HMAC-SHA256(auth_secret, \"sfmc-module:\" + moduleId).hex\n *\n * auth_secret \u4F18\u5148\u7EA7:\n * 1. env.AUTH_TOKEN\n * 2. \u542F\u52A8\u65F6\u968F\u673A\u751F\u6210(\u65E0 AUTH_TOKEN \u65F6),\u5199\u5230 module-tokens.json,\n * \u53EA\u8B66\u544A\u4E00\u6B21(\u6BCF\u6B21\u91CD\u542F\u6A21\u5757 token \u90FD\u53D8,SAPI host \u5FC5\u987B\u91CD\u8BFB\u6587\u4EF6)\n *\n * \u6821\u9A8C:\n * - HTTP `Authorization: Bearer <module_token>` \u5934\n * - Query `?moduleId=<id>`\n * - \u4E24\u90FD\u5339\u914D = \u8C03\u7528\u65B9\u8EAB\u4EFD\n * - \u6821\u9A8C\u8C03\u7528\u65B9 moduleId \u5728 enabled \u5217\u8868(\u5426\u5219 403)\n */\n\nimport { readJson, writeJson, type TokenStore } from \"@sfmc-bds/sdk/node/config\";\nimport { createHmac, randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { log } from \"./lib/log.js\";\n\nexport interface ModuleAuthMap {\n /** moduleId \u2192 hex token */\n tokens: Record<string, string>;\n /** \u7528\u4E8E\u6D3E\u751F token \u7684 secret (env.AUTH_TOKEN \u6216\u672C\u6B21\u542F\u52A8\u968F\u673A\u751F\u6210) */\n secret: string;\n}\n\nconst IDENT = /^[A-Za-z0-9_\\-]+$/;\n\nfunction safeId(id: string): string {\n if (!IDENT.test(id)) throw new Error(`[auth] invalid module id: ${id}`);\n return id;\n}\n\n/** token \u6587\u4EF6\u4E0E SQLite \u540C\u76EE\u5F55\uFF08\u7531 dbDir \u51B3\u5B9A\uFF0C\u907F\u514D\u5411\u5BFC\u9009\u76EE\u5F55\u524D\u5C31\u521B\u5EFA ROOT/data\uFF09 */\nexport function moduleTokensFile(dbPath: string): string {\n return join(dirname(dbPath), \"module-tokens.json\");\n}\n\nexport function deriveToken(moduleId: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`sfmc-module:${safeId(moduleId)}`).digest(\"hex\");\n}\n\n/**\n * \u542F\u52A8\u65F6\u8C03\u7528\u4E00\u6B21:\n * - \u628A env.AUTH_TOKEN \u5F53 secret\n * - \u7ED9\u6BCF\u4E2A enabled moduleId \u6D3E\u751F token\n * - \u5199 module-tokens.json\uFF08\u4E0E DB \u540C\u76EE\u5F55\uFF09\n * - \u63A7\u5236\u53F0\u6253\u5370\u6458\u8981(env var SFMC_LOG_MODULE_TOKEN=1 \u65F6\u6253\u5B8C\u6574)\n */\nexport function buildModuleAuth(opts: {\n dbPath: string;\n envAuthToken: string;\n enabledModuleIds: string[];\n}): ModuleAuthMap {\n const secret = opts.envAuthToken || randomBytes(32).toString(\"hex\");\n const tokens: Record<string, string> = {};\n for (const id of opts.enabledModuleIds) {\n tokens[id] = deriveToken(id, secret);\n }\n\n const outFile = moduleTokensFile(opts.dbPath);\n writeJson(outFile, {\n tokens,\n secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !opts.envAuthToken,\n });\n\n log.success(\n `[auth] \u5DF2\u4E3A ${opts.enabledModuleIds.length} \u4E2A\u6A21\u5757\u6D3E\u751F HMAC token,\u5199\u5165 ${outFile}`\n );\n if (!opts.envAuthToken) {\n log.warn(\n \"[auth] \u672A\u914D\u7F6E env.AUTH_TOKEN(\u51B2\u7A81 config http_auth),\u672C\u6B21\u542F\u52A8\u4F7F\u7528\u4E86\u968F\u673A secret;\"\n + \" \u91CD\u542F\u540E token \u4F1A\u53D8,host-bootstrap \u5FC5\u987B\u6BCF\u6B21\u91CD\u65B0\u8BFB module-tokens.json\"\n );\n }\n if (process.env.SFMC_LOG_MODULE_TOKEN === \"1\") {\n log.info(\"[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):\");\n for (const [id, t] of Object.entries(tokens)) {\n console.log(` ${id} = ${t}`);\n }\n } else {\n const lines = Object.entries(tokens)\n .map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`)\n .join(\"\\n\");\n log.info(`[auth] token \u6458\u8981:\\n${lines}`);\n }\n\n return { tokens, secret };\n}\n\nexport function loadModuleAuth(dbPath: string): ModuleAuthMap | null {\n const parsed = readJson<TokenStore>(moduleTokensFile(dbPath));\n if (!parsed || !parsed.tokens || !parsed.secret) return null;\n return { tokens: parsed.tokens, secret: parsed.secret };\n}\n\n/** \u628A\u5F53\u524D auth map \u5199\u56DE module-tokens.json(\u70ED\u66F4\u65B0 token \u65F6\u590D\u7528) */\nexport function persistModuleAuth(dbPath: string, auth: ModuleAuthMap, envAuthToken: string): void {\n const outFile = moduleTokensFile(dbPath);\n writeJson(outFile, {\n tokens: auth.tokens,\n secret: auth.secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !envAuthToken,\n } satisfies TokenStore);\n}\n\n/**\n * \u786E\u4FDD moduleId \u5728 auth.tokens \u4E2D\u6709\u6D3E\u751F\u503C(\u590D\u7528\u73B0\u6709 secret,\u52FF\u91CD\u5EFA\u968F\u673A secret)\u3002\n * @returns \u662F\u5426\u65B0\u5199\u5165\u4E86 token\n */\nexport function ensureModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (auth.tokens[moduleId]) return false;\n auth.tokens[moduleId] = deriveToken(moduleId, auth.secret);\n return true;\n}\n\n/** \u7981\u7528\u65F6\u64A4\u9500\u5185\u5B58\u4E2D\u7684 token(\u78C1\u76D8\u7531 persistModuleAuth \u540C\u6B65) */\nexport function revokeModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (!(moduleId in auth.tokens)) return false;\n delete auth.tokens[moduleId];\n return true;\n}\n\n/**\n * \u6821\u9A8C\u8BF7\u6C42\u65B9\u8EAB\u4EFD:\n * - Bearer \u5934 / X-Module-Token \u4E8C\u9009\u4E00\n * - ?moduleId=<id> \u5FC5\u987B\u5B58\u5728\n * - \u6A21\u5757\u5FC5\u987B\u5728 enabledModuleIds \u96C6\u5408\u4E2D\n * - token \u5FC5\u987B = deriveToken(moduleId, secret)\n * \u8FD4\u56DE\u6A21\u5757 ID \u6216 null\u3002\n */\nexport function verifyModuleAuth(opts: {\n headers: NodeJS.Dict<string | string[]>;\n params: URLSearchParams;\n auth: ModuleAuthMap;\n enabledModuleIds: Set<string>;\n}): string | null {\n const moduleId = opts.params.get(\"moduleId\") || \"\";\n if (!moduleId || !opts.enabledModuleIds.has(moduleId)) return null;\n\n let provided = \"\";\n const auth = opts.headers[\"authorization\"];\n const token = opts.headers[\"x-module-token\"];\n if (typeof auth === \"string\" && auth.startsWith(\"Bearer \")) {\n provided = auth.slice(7);\n } else if (typeof token === \"string\") {\n provided = token;\n }\n if (!provided) return null;\n\n const expected = opts.auth.tokens[moduleId];\n if (!expected) return null;\n // constant-time \u6BD4\u8F83\n if (provided.length !== expected.length) return null;\n let diff = 0;\n for (let i = 0; i < provided.length; i++) {\n diff |= provided.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0 ? moduleId : null;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * module-auth.ts \u2014 \u6A21\u5757\u8EAB\u4EFD\u7684 HMAC token \u6D3E\u751F\u4E0E\u6821\u9A8C\n *\n * \u4E24\u5957\u5E76\u5B58:\n * - `env.AUTH_TOKEN` (config db_config.json http_auth):sfmc \u7BA1\u63A7 / \u5E73\u53F0\u5185\u90E8\u7528\n * - `moduleTokens[moduleId]`:db-server \u7ED9\u6BCF\u4E2A enabled \u6A21\u5757\u5728\u542F\u52A8\u65F6\u6D3E\u751F,\n * \u5199\u5230\u300C\u4E0E\u6570\u636E\u5E93\u540C\u76EE\u5F55\u300D\u7684 module-tokens.json\uFF08\u8DDF db_config.dbDir \u8D70\uFF0C\u52FF\u5199\u6B7B ROOT/data\uFF09,\n * SAPI \u7ECF loopback API \u6CE8\u5165 setDbModuleContext\u3002\n *\n * \u6D3E\u751F\u516C\u5F0F:\n * module_token = HMAC-SHA256(auth_secret, \"sfmc-module:\" + moduleId).hex\n *\n * auth_secret \u4F18\u5148\u7EA7:\n * 1. env.AUTH_TOKEN\n * 2. \u542F\u52A8\u65F6\u968F\u673A\u751F\u6210(\u65E0 AUTH_TOKEN \u65F6),\u5199\u5230 module-tokens.json,\n * \u53EA\u8B66\u544A\u4E00\u6B21(\u6BCF\u6B21\u91CD\u542F\u6A21\u5757 token \u90FD\u53D8,SAPI host \u5FC5\u987B\u91CD\u8BFB\u6587\u4EF6)\n *\n * \u6821\u9A8C:\n * - HTTP `Authorization: Bearer <module_token>` \u5934\n * - Query `?moduleId=<id>`\n * - \u4E24\u90FD\u5339\u914D = \u8C03\u7528\u65B9\u8EAB\u4EFD\n * - \u6821\u9A8C\u8C03\u7528\u65B9 moduleId \u5728 enabled \u5217\u8868(\u5426\u5219 403)\n */\n\nimport { readJson, writeJson, type TokenStore } from \"@sfmc-bds/sdk/node/config\";\nimport { createHmac, randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { log } from \"./lib/log.js\";\n\nexport interface ModuleAuthMap {\n /** moduleId \u2192 hex token */\n tokens: Record<string, string>;\n /** \u7528\u4E8E\u6D3E\u751F token \u7684 secret (env.AUTH_TOKEN \u6216\u672C\u6B21\u542F\u52A8\u968F\u673A\u751F\u6210) */\n secret: string;\n}\n\nconst IDENT = /^[A-Za-z0-9_\\-]+$/;\n\nfunction safeId(id: string): string {\n if (!IDENT.test(id)) throw new Error(`[auth] invalid module id: ${id}`);\n return id;\n}\n\n/** token \u6587\u4EF6\u4E0E SQLite \u540C\u76EE\u5F55\uFF08\u7531 dbDir \u51B3\u5B9A\uFF0C\u907F\u514D\u5411\u5BFC\u9009\u76EE\u5F55\u524D\u5C31\u521B\u5EFA ROOT/data\uFF09 */\nexport function moduleTokensFile(dbPath: string): string {\n return join(dirname(dbPath), \"module-tokens.json\");\n}\n\nexport function deriveToken(moduleId: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`sfmc-module:${safeId(moduleId)}`).digest(\"hex\");\n}\n\n/**\n * \u542F\u52A8\u65F6\u8C03\u7528\u4E00\u6B21:\n * - \u628A env.AUTH_TOKEN \u5F53 secret\n * - \u7ED9\u6BCF\u4E2A enabled moduleId \u6D3E\u751F token\n * - \u5199 module-tokens.json\uFF08\u4E0E DB \u540C\u76EE\u5F55\uFF09\n * - \u63A7\u5236\u53F0\u6253\u5370\u6458\u8981(env var SFMC_LOG_MODULE_TOKEN=1 \u65F6\u6253\u5B8C\u6574)\n */\nexport function buildModuleAuth(opts: {\n dbPath: string;\n envAuthToken: string;\n enabledModuleIds: string[];\n}): ModuleAuthMap {\n const secret = opts.envAuthToken || randomBytes(32).toString(\"hex\");\n const tokens: Record<string, string> = {};\n for (const id of opts.enabledModuleIds) {\n tokens[id] = deriveToken(id, secret);\n }\n\n const outFile = moduleTokensFile(opts.dbPath);\n writeJson(outFile, {\n tokens,\n secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !opts.envAuthToken,\n });\n\n log.success(\n `[auth] \u5DF2\u4E3A ${opts.enabledModuleIds.length} \u4E2A\u6A21\u5757\u6D3E\u751F HMAC token,\u5199\u5165 ${outFile}`\n );\n if (!opts.envAuthToken) {\n log.warn(\n \"[auth] \u672A\u914D\u7F6E env.AUTH_TOKEN(\u51B2\u7A81 config http_auth),\u672C\u6B21\u542F\u52A8\u4F7F\u7528\u4E86\u968F\u673A secret;\"\n + \" \u91CD\u542F\u540E token \u4F1A\u53D8,host-bootstrap \u5FC5\u987B\u6BCF\u6B21\u91CD\u65B0\u8BFB module-tokens.json\"\n );\n }\n if (process.env.SFMC_LOG_MODULE_TOKEN === \"1\") {\n log.info(\"[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):\");\n for (const [id, t] of Object.entries(tokens)) {\n log.info(` ${id} = ${t}`);\n }\n } else {\n const lines = Object.entries(tokens)\n .map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`)\n .join(\"\\n\");\n log.info(`[auth] token \u6458\u8981:\\n${lines}`);\n }\n\n return { tokens, secret };\n}\n\nexport function loadModuleAuth(dbPath: string): ModuleAuthMap | null {\n const parsed = readJson<TokenStore>(moduleTokensFile(dbPath));\n if (!parsed || !parsed.tokens || !parsed.secret) return null;\n return { tokens: parsed.tokens, secret: parsed.secret };\n}\n\n/** \u628A\u5F53\u524D auth map \u5199\u56DE module-tokens.json(\u70ED\u66F4\u65B0 token \u65F6\u590D\u7528) */\nexport function persistModuleAuth(dbPath: string, auth: ModuleAuthMap, envAuthToken: string): void {\n const outFile = moduleTokensFile(dbPath);\n writeJson(outFile, {\n tokens: auth.tokens,\n secret: auth.secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !envAuthToken,\n } satisfies TokenStore);\n}\n\n/**\n * \u786E\u4FDD moduleId \u5728 auth.tokens \u4E2D\u6709\u6D3E\u751F\u503C(\u590D\u7528\u73B0\u6709 secret,\u52FF\u91CD\u5EFA\u968F\u673A secret)\u3002\n * @returns \u662F\u5426\u65B0\u5199\u5165\u4E86 token\n */\nexport function ensureModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (auth.tokens[moduleId]) return false;\n auth.tokens[moduleId] = deriveToken(moduleId, auth.secret);\n return true;\n}\n\n/** \u7981\u7528\u65F6\u64A4\u9500\u5185\u5B58\u4E2D\u7684 token(\u78C1\u76D8\u7531 persistModuleAuth \u540C\u6B65) */\nexport function revokeModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (!(moduleId in auth.tokens)) return false;\n delete auth.tokens[moduleId];\n return true;\n}\n\n/**\n * \u6821\u9A8C\u8BF7\u6C42\u65B9\u8EAB\u4EFD:\n * - Bearer \u5934 / X-Module-Token \u4E8C\u9009\u4E00\n * - ?moduleId=<id> \u5FC5\u987B\u5B58\u5728\n * - \u6A21\u5757\u5FC5\u987B\u5728 enabledModuleIds \u96C6\u5408\u4E2D\n * - token \u5FC5\u987B = deriveToken(moduleId, secret)\n * \u8FD4\u56DE\u6A21\u5757 ID \u6216 null\u3002\n */\nexport function verifyModuleAuth(opts: {\n headers: NodeJS.Dict<string | string[]>;\n params: URLSearchParams;\n auth: ModuleAuthMap;\n enabledModuleIds: Set<string>;\n}): string | null {\n const moduleId = opts.params.get(\"moduleId\") || \"\";\n if (!moduleId || !opts.enabledModuleIds.has(moduleId)) return null;\n\n let provided = \"\";\n const auth = opts.headers[\"authorization\"];\n const token = opts.headers[\"x-module-token\"];\n if (typeof auth === \"string\" && auth.startsWith(\"Bearer \")) {\n provided = auth.slice(7);\n } else if (typeof token === \"string\") {\n provided = token;\n }\n if (!provided) return null;\n\n const expected = opts.auth.tokens[moduleId];\n if (!expected) return null;\n // constant-time \u6BD4\u8F83\n if (provided.length !== expected.length) return null;\n let diff = 0;\n for (let i = 0; i < provided.length; i++) {\n diff |= provided.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0 ? moduleId : null;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * project-root.ts — 仓根唯一解析点(DRY/DIP:env / log 勿各自上溯)
3
+ */
4
+ /** SFMC_ROOT > 相对 db-server/src 上溯两级 */
5
+ export declare const PROJECT_ROOT: string;
6
+ //# sourceMappingURL=project-root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-root.d.ts","sourceRoot":"","sources":["../src/project-root.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,wCAAwC;AACxC,eAAO,MAAM,YAAY,EAAE,MAAsD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { resolveRuntimeRoot } from "@sfmc-bds/sdk/node/config";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const HERE = dirname(fileURLToPath(import.meta.url));
5
+ const PROJECT_ROOT = resolveRuntimeRoot(resolve(HERE, "..", ".."));
6
+ export {
7
+ PROJECT_ROOT
8
+ };
9
+ //# sourceMappingURL=project-root.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/project-root.ts"],
4
+ "sourcesContent": ["/**\n * project-root.ts \u2014 \u4ED3\u6839\u552F\u4E00\u89E3\u6790\u70B9\uFF08DRY/DIP\uFF1Aenv / log \u52FF\u5404\u81EA\u4E0A\u6EAF\uFF09\n */\n\nimport { resolveRuntimeRoot } from \"@sfmc-bds/sdk/node/config\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\n/** SFMC_ROOT > \u76F8\u5BF9 db-server/src \u4E0A\u6EAF\u4E24\u7EA7 */\nexport const PROJECT_ROOT: string = resolveRuntimeRoot(resolve(HERE, \"..\", \"..\"));\n"],
5
+ "mappings": "AAIA,SAAS,0BAA0B;AACnC,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;AAE9B,MAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AAG5C,MAAM,eAAuB,mBAAmB,QAAQ,MAAM,MAAM,IAAI,CAAC;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@sfmc-bds/db-server",
3
- "version": "0.2.0-beta.0",
4
- "description": "SFMC SQLite HTTP REST backend — configs, modules, gameplay data, QQ message relay",
5
- "type": "module",
6
- "license": "ISC",
3
+ "version": "0.2.0-beta.5",
4
+ "description": "SFMC SQLite HTTP REST backend — configs, modules, gameplay data",
7
5
  "author": "Shiroha7z",
6
+ "license": "AGPL-3.0-only",
7
+ "type": "module",
8
8
  "homepage": "https://github.com/DogeLakeDev/ScriptsForMinecraftServer/tree/main/db-server#readme",
9
9
  "repository": {
10
10
  "type": "git",
@@ -16,11 +16,14 @@
16
16
  },
17
17
  "keywords": [
18
18
  "minecraft-bedrock",
19
- "sfmc",
20
- "sqlite",
21
19
  "rest-api",
22
- "scriptsforminecraftserver"
20
+ "scriptsforminecraftserver",
21
+ "sfmc",
22
+ "sqlite"
23
23
  ],
24
+ "engines": {
25
+ "node": ">=22.13.0"
26
+ },
24
27
  "main": "dist/index.js",
25
28
  "types": "./dist/index.d.ts",
26
29
  "files": [
@@ -28,22 +31,19 @@
28
31
  "README.md"
29
32
  ],
30
33
  "scripts": {
31
- "start": "node dist/index.js",
32
- "dev": "tsx src/index.ts",
33
- "build": "node ../scripts/esbuild-transpile.mjs --dts",
34
- "typecheck": "tsc7 --noEmit",
34
+ "build": "sfmc-esbuild-transpile --dts",
35
35
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
36
- "test": "npm run build && node --test dist/*.test.js",
36
+ "dev": "tsx src/index.ts",
37
37
  "format": "prettier --write \"src/**/*.{ts,tsx,js,json}\"",
38
- "prepublishOnly": "npm run build"
38
+ "prepublishOnly": "npm run build",
39
+ "start": "node dist/index.js",
40
+ "test": "node --test dist/*.test.js",
41
+ "test:api": "npm run build && node scripts/test-db-api.mjs",
42
+ "typecheck": "tsc7 --noEmit"
39
43
  },
40
44
  "dependencies": {
41
- "@sfmc-bds/sdk": "^0.2.0-beta.0",
42
- "sql-template-strings": "^2.2.2",
43
- "ws": "^8.21.1"
44
- },
45
- "engines": {
46
- "node": ">=22.13.0"
45
+ "@sfmc-bds/sdk": "^0.2.0-beta.6",
46
+ "sql-template-strings": "^2.2.2"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",