@humbdb/driver-contract 0.0.1
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/LICENSE +21 -0
- package/README.md +6 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Humb contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# @humbdb/driver-contract
|
|
2
|
+
|
|
3
|
+
Engine-agnostic database adapter contracts. Concrete engine drivers implement `DatabaseAdapter`.
|
|
4
|
+
|
|
5
|
+
To add a new engine, create a `packages/drivers/<engine>` package that implements these interfaces.
|
|
6
|
+
See [`ARCHITECTURE.md`](../../../ARCHITECTURE.md).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ConnectionTarget, DatabaseOverview, TableMetadata, RowPage } from '@humbdb/core';
|
|
2
|
+
|
|
3
|
+
/** A live, engine-specific connection to a single database. */
|
|
4
|
+
interface DatabaseAdapter {
|
|
5
|
+
/** The engine identifier, e.g. "postgres". */
|
|
6
|
+
readonly engine: string;
|
|
7
|
+
/** Establish the underlying connection/pool. */
|
|
8
|
+
connect(): Promise<void>;
|
|
9
|
+
/** Tear down the connection/pool and release resources. */
|
|
10
|
+
disconnect(): Promise<void>;
|
|
11
|
+
/** Lightweight connectivity check. */
|
|
12
|
+
ping(): Promise<boolean>;
|
|
13
|
+
/** Human-readable engine name + version, e.g. "PostgreSQL 16.1", "SQLite 3.45.0". */
|
|
14
|
+
getVersion(): Promise<string>;
|
|
15
|
+
/** Introspect the overall structure (schemas and tables). */
|
|
16
|
+
getOverview(): Promise<DatabaseOverview>;
|
|
17
|
+
/** Introspect a single table's columns and metadata. */
|
|
18
|
+
getTable(schema: string, table: string): Promise<TableMetadata>;
|
|
19
|
+
/** Fetch a page of rows for a table. */
|
|
20
|
+
getRows(schema: string, table: string, page: number, pageSize: number): Promise<RowPage>;
|
|
21
|
+
/** Execute a read-only (SELECT-style) query. Implementations must reject mutations. */
|
|
22
|
+
runReadOnlyQuery(sql: string): Promise<RowPage>;
|
|
23
|
+
}
|
|
24
|
+
/** Creates {@link DatabaseAdapter} instances for targets a given engine supports. */
|
|
25
|
+
interface AdapterFactory {
|
|
26
|
+
readonly engine: string;
|
|
27
|
+
/** Whether this factory can handle the given connection target. */
|
|
28
|
+
supports(target: ConnectionTarget): boolean;
|
|
29
|
+
/** Create (but do not yet connect) an adapter for the target. */
|
|
30
|
+
create(target: ConnectionTarget): DatabaseAdapter;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Thrown when no registered adapter supports a connection target. */
|
|
34
|
+
declare class UnsupportedEngineError extends Error {
|
|
35
|
+
constructor(engine: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a query passed to `DatabaseAdapter.runReadOnlyQuery` violates Humb's read-only
|
|
39
|
+
* policy. Engine-agnostic so `packages/server` can catch it (and return 400) without depending on
|
|
40
|
+
* any concrete engine package - every engine's query runner throws this same class.
|
|
41
|
+
*/
|
|
42
|
+
declare class ReadOnlyViolationError extends Error {
|
|
43
|
+
constructor(message: string);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Resolve the first factory that supports the target, or throw. */
|
|
47
|
+
declare function resolveAdapter(factories: readonly AdapterFactory[], target: ConnectionTarget): DatabaseAdapter;
|
|
48
|
+
|
|
49
|
+
/** A resolved, safely-bounded page request. */
|
|
50
|
+
interface ResolvedPageRequest {
|
|
51
|
+
readonly page: number;
|
|
52
|
+
readonly pageSize: number;
|
|
53
|
+
readonly offset: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Clamp a requested page/pageSize into safe, non-negative bounds. Shared by every engine adapter so
|
|
57
|
+
* pagination behaves identically regardless of which database is behind it - do not reimplement
|
|
58
|
+
* this per engine.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolvePageRequest(page: number, pageSize: number): ResolvedPageRequest;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Assert that a SQL string is a single read-only statement. Engine-agnostic: pure text scanning,
|
|
64
|
+
* shared by every engine adapter so the heuristic behaves identically regardless of which database
|
|
65
|
+
* is behind it.
|
|
66
|
+
*
|
|
67
|
+
* Throws {@link ReadOnlyViolationError} otherwise. This is a defense-in-depth check; each adapter's
|
|
68
|
+
* `runReadOnlyQuery` must also enforce read-only at the engine level as the authoritative guarantee
|
|
69
|
+
* (see this module's top-level comment).
|
|
70
|
+
*/
|
|
71
|
+
declare function assertReadOnly(sql: string): void;
|
|
72
|
+
|
|
73
|
+
export { type AdapterFactory, type DatabaseAdapter, ReadOnlyViolationError, type ResolvedPageRequest, UnsupportedEngineError, assertReadOnly, resolveAdapter, resolvePageRequest };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var UnsupportedEngineError = class extends Error {
|
|
3
|
+
constructor(engine) {
|
|
4
|
+
super(`No database adapter is registered for engine "${engine}".`);
|
|
5
|
+
this.name = "UnsupportedEngineError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var ReadOnlyViolationError = class extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "ReadOnlyViolationError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/resolve.ts
|
|
16
|
+
function resolveAdapter(factories, target) {
|
|
17
|
+
const factory = factories.find((candidate) => candidate.supports(target));
|
|
18
|
+
if (!factory) {
|
|
19
|
+
throw new UnsupportedEngineError(target.engine);
|
|
20
|
+
}
|
|
21
|
+
return factory.create(target);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/pagination.ts
|
|
25
|
+
var MAX_PAGE_SIZE = 200;
|
|
26
|
+
function resolvePageRequest(page, pageSize) {
|
|
27
|
+
const safePage = Math.max(0, Math.floor(page));
|
|
28
|
+
const safePageSize = Math.min(Math.max(1, Math.floor(pageSize)), MAX_PAGE_SIZE);
|
|
29
|
+
return { page: safePage, pageSize: safePageSize, offset: safePage * safePageSize };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/read-only.ts
|
|
33
|
+
var ALLOWED_LEADING_KEYWORDS = ["select", "with", "explain", "show", "table", "values"];
|
|
34
|
+
var FORBIDDEN_KEYWORDS = [
|
|
35
|
+
"insert",
|
|
36
|
+
"update",
|
|
37
|
+
"delete",
|
|
38
|
+
"merge",
|
|
39
|
+
"truncate",
|
|
40
|
+
"drop",
|
|
41
|
+
"alter",
|
|
42
|
+
"create",
|
|
43
|
+
"grant",
|
|
44
|
+
"revoke",
|
|
45
|
+
"copy",
|
|
46
|
+
"call",
|
|
47
|
+
"do",
|
|
48
|
+
"vacuum",
|
|
49
|
+
"reindex",
|
|
50
|
+
"refresh",
|
|
51
|
+
"lock",
|
|
52
|
+
"comment",
|
|
53
|
+
"security"
|
|
54
|
+
];
|
|
55
|
+
function stripComments(sql) {
|
|
56
|
+
return sql.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
57
|
+
}
|
|
58
|
+
function stripLiterals(sql) {
|
|
59
|
+
return sql.replace(/\$([A-Za-z_][A-Za-z0-9_]*)?\$[\s\S]*?\$\1\$/g, " ").replace(/'(?:[^']|'')*'/g, " ").replace(/"(?:[^"]|"")*"/g, " ");
|
|
60
|
+
}
|
|
61
|
+
function findForbiddenKeyword(sql) {
|
|
62
|
+
const lower = sql.toLowerCase();
|
|
63
|
+
return FORBIDDEN_KEYWORDS.find((keyword) => new RegExp(`\\b${keyword}\\b`).test(lower));
|
|
64
|
+
}
|
|
65
|
+
function assertReadOnly(sql) {
|
|
66
|
+
const withoutComments = stripComments(sql).trim();
|
|
67
|
+
if (!withoutComments) {
|
|
68
|
+
throw new ReadOnlyViolationError("Empty query.");
|
|
69
|
+
}
|
|
70
|
+
const withoutTrailingSemicolon = withoutComments.replace(/;\s*$/, "");
|
|
71
|
+
if (withoutTrailingSemicolon.includes(";")) {
|
|
72
|
+
throw new ReadOnlyViolationError(
|
|
73
|
+
"Multiple statements are not allowed in the read-only query runner."
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const firstKeyword = withoutTrailingSemicolon.split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
77
|
+
if (!ALLOWED_LEADING_KEYWORDS.includes(firstKeyword)) {
|
|
78
|
+
throw new ReadOnlyViolationError(
|
|
79
|
+
`Only read-only statements are allowed (${ALLOWED_LEADING_KEYWORDS.join(", ").toUpperCase()}). Received a statement starting with "${firstKeyword.toUpperCase()}".`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const forbidden = findForbiddenKeyword(stripLiterals(withoutTrailingSemicolon));
|
|
83
|
+
if (forbidden) {
|
|
84
|
+
throw new ReadOnlyViolationError(
|
|
85
|
+
`Only read-only statements are allowed. The query contains a disallowed keyword: "${forbidden.toUpperCase()}" (e.g. inside a writable CTE, which Postgres allows even though the statement starts with a read-only keyword).`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
ReadOnlyViolationError,
|
|
91
|
+
UnsupportedEngineError,
|
|
92
|
+
assertReadOnly,
|
|
93
|
+
resolveAdapter,
|
|
94
|
+
resolvePageRequest
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/resolve.ts","../src/pagination.ts","../src/read-only.ts"],"sourcesContent":["/** Thrown when no registered adapter supports a connection target. */\nexport class UnsupportedEngineError extends Error {\n constructor(engine: string) {\n super(`No database adapter is registered for engine \"${engine}\".`);\n this.name = \"UnsupportedEngineError\";\n }\n}\n\n/**\n * Thrown when a query passed to `DatabaseAdapter.runReadOnlyQuery` violates Humb's read-only\n * policy. Engine-agnostic so `packages/server` can catch it (and return 400) without depending on\n * any concrete engine package - every engine's query runner throws this same class.\n */\nexport class ReadOnlyViolationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ReadOnlyViolationError\";\n }\n}\n","import type { ConnectionTarget } from \"@humbdb/core\";\nimport type { AdapterFactory, DatabaseAdapter } from \"./contract.js\";\nimport { UnsupportedEngineError } from \"./errors.js\";\n\n/** Resolve the first factory that supports the target, or throw. */\nexport function resolveAdapter(\n factories: readonly AdapterFactory[],\n target: ConnectionTarget\n): DatabaseAdapter {\n const factory = factories.find((candidate) => candidate.supports(target));\n if (!factory) {\n throw new UnsupportedEngineError(target.engine);\n }\n return factory.create(target);\n}\n","/** A resolved, safely-bounded page request. */\nexport interface ResolvedPageRequest {\n readonly page: number;\n readonly pageSize: number;\n readonly offset: number;\n}\n\nconst MAX_PAGE_SIZE = 200;\n\n/**\n * Clamp a requested page/pageSize into safe, non-negative bounds. Shared by every engine adapter so\n * pagination behaves identically regardless of which database is behind it - do not reimplement\n * this per engine.\n */\nexport function resolvePageRequest(page: number, pageSize: number): ResolvedPageRequest {\n const safePage = Math.max(0, Math.floor(page));\n const safePageSize = Math.min(Math.max(1, Math.floor(pageSize)), MAX_PAGE_SIZE);\n return { page: safePage, pageSize: safePageSize, offset: safePage * safePageSize };\n}\n","import { ReadOnlyViolationError } from \"./errors.js\";\n\nexport { ReadOnlyViolationError } from \"./errors.js\";\n\nconst ALLOWED_LEADING_KEYWORDS = [\"select\", \"with\", \"explain\", \"show\", \"table\", \"values\"];\n\n// Data-modifying/DDL/permission keywords that must never appear anywhere in the statement, not just\n// as the leading keyword - e.g. Postgres allows *writable CTEs*\n// (`WITH x AS (DELETE FROM t RETURNING *) SELECT * FROM x`), which start with the allowed \"with\"\n// keyword but perform a real DELETE. This list is a heuristic, defense-in-depth layer, not the\n// authoritative guarantee - every engine adapter's `runReadOnlyQuery` must also enforce read-only at\n// the engine level (a Postgres `READ ONLY` transaction, a SQLite read-only connection, etc.), which\n// catches whatever this scan misses.\nconst FORBIDDEN_KEYWORDS = [\n \"insert\",\n \"update\",\n \"delete\",\n \"merge\",\n \"truncate\",\n \"drop\",\n \"alter\",\n \"create\",\n \"grant\",\n \"revoke\",\n \"copy\",\n \"call\",\n \"do\",\n \"vacuum\",\n \"reindex\",\n \"refresh\",\n \"lock\",\n \"comment\",\n \"security\"\n];\n\n/** Remove SQL comments so keyword detection is not fooled by them. */\nfunction stripComments(sql: string): string {\n return sql.replace(/--[^\\n]*/g, \" \").replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \");\n}\n\n/**\n * Remove string/identifier literals so keyword detection isn't fooled by data that happens to\n * contain a forbidden word (e.g. a string literal or a quoted column named \"update\").\n */\nfunction stripLiterals(sql: string): string {\n return sql\n .replace(/\\$([A-Za-z_][A-Za-z0-9_]*)?\\$[\\s\\S]*?\\$\\1\\$/g, \" \") // dollar-quoted strings (Postgres)\n .replace(/'(?:[^']|'')*'/g, \" \") // single-quoted string literals\n .replace(/\"(?:[^\"]|\"\")*\"/g, \" \"); // double-quoted identifiers\n}\n\nfunction findForbiddenKeyword(sql: string): string | undefined {\n const lower = sql.toLowerCase();\n return FORBIDDEN_KEYWORDS.find((keyword) => new RegExp(`\\\\b${keyword}\\\\b`).test(lower));\n}\n\n/**\n * Assert that a SQL string is a single read-only statement. Engine-agnostic: pure text scanning,\n * shared by every engine adapter so the heuristic behaves identically regardless of which database\n * is behind it.\n *\n * Throws {@link ReadOnlyViolationError} otherwise. This is a defense-in-depth check; each adapter's\n * `runReadOnlyQuery` must also enforce read-only at the engine level as the authoritative guarantee\n * (see this module's top-level comment).\n */\nexport function assertReadOnly(sql: string): void {\n const withoutComments = stripComments(sql).trim();\n if (!withoutComments) {\n throw new ReadOnlyViolationError(\"Empty query.\");\n }\n\n const withoutTrailingSemicolon = withoutComments.replace(/;\\s*$/, \"\");\n if (withoutTrailingSemicolon.includes(\";\")) {\n throw new ReadOnlyViolationError(\n \"Multiple statements are not allowed in the read-only query runner.\"\n );\n }\n\n const firstKeyword = withoutTrailingSemicolon.split(/\\s+/)[0]?.toLowerCase() ?? \"\";\n if (!ALLOWED_LEADING_KEYWORDS.includes(firstKeyword)) {\n throw new ReadOnlyViolationError(\n `Only read-only statements are allowed (${ALLOWED_LEADING_KEYWORDS.join(\", \").toUpperCase()}). ` +\n `Received a statement starting with \"${firstKeyword.toUpperCase()}\".`\n );\n }\n\n const forbidden = findForbiddenKeyword(stripLiterals(withoutTrailingSemicolon));\n if (forbidden) {\n throw new ReadOnlyViolationError(\n `Only read-only statements are allowed. The query contains a disallowed keyword: ` +\n `\"${forbidden.toUpperCase()}\" (e.g. inside a writable CTE, which Postgres allows even though ` +\n `the statement starts with a read-only keyword).`\n );\n }\n}\n"],"mappings":";AACO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAY,QAAgB;AAC1B,UAAM,iDAAiD,MAAM,IAAI;AACjE,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACbO,SAAS,eACd,WACA,QACiB;AACjB,QAAM,UAAU,UAAU,KAAK,CAAC,cAAc,UAAU,SAAS,MAAM,CAAC;AACxE,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,uBAAuB,OAAO,MAAM;AAAA,EAChD;AACA,SAAO,QAAQ,OAAO,MAAM;AAC9B;;;ACPA,IAAM,gBAAgB;AAOf,SAAS,mBAAmB,MAAc,UAAuC;AACtF,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC;AAC7C,QAAM,eAAe,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,CAAC,GAAG,aAAa;AAC9E,SAAO,EAAE,MAAM,UAAU,UAAU,cAAc,QAAQ,WAAW,aAAa;AACnF;;;ACdA,IAAM,2BAA2B,CAAC,UAAU,QAAQ,WAAW,QAAQ,SAAS,QAAQ;AASxF,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,SAAS,cAAc,KAAqB;AAC1C,SAAO,IAAI,QAAQ,aAAa,GAAG,EAAE,QAAQ,qBAAqB,GAAG;AACvE;AAMA,SAAS,cAAc,KAAqB;AAC1C,SAAO,IACJ,QAAQ,gDAAgD,GAAG,EAC3D,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,mBAAmB,GAAG;AACnC;AAEA,SAAS,qBAAqB,KAAiC;AAC7D,QAAM,QAAQ,IAAI,YAAY;AAC9B,SAAO,mBAAmB,KAAK,CAAC,YAAY,IAAI,OAAO,MAAM,OAAO,KAAK,EAAE,KAAK,KAAK,CAAC;AACxF;AAWO,SAAS,eAAe,KAAmB;AAChD,QAAM,kBAAkB,cAAc,GAAG,EAAE,KAAK;AAChD,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI,uBAAuB,cAAc;AAAA,EACjD;AAEA,QAAM,2BAA2B,gBAAgB,QAAQ,SAAS,EAAE;AACpE,MAAI,yBAAyB,SAAS,GAAG,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,yBAAyB,MAAM,KAAK,EAAE,CAAC,GAAG,YAAY,KAAK;AAChF,MAAI,CAAC,yBAAyB,SAAS,YAAY,GAAG;AACpD,UAAM,IAAI;AAAA,MACR,0CAA0C,yBAAyB,KAAK,IAAI,EAAE,YAAY,CAAC,0CAClD,aAAa,YAAY,CAAC;AAAA,IACrE;AAAA,EACF;AAEA,QAAM,YAAY,qBAAqB,cAAc,wBAAwB,CAAC;AAC9E,MAAI,WAAW;AACb,UAAM,IAAI;AAAA,MACR,oFACM,UAAU,YAAY,CAAC;AAAA,IAE/B;AAAA,EACF;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@humbdb/driver-contract",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Engine-agnostic database adapter contracts for Humb.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@humbdb/core": "0.0.1"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@humbdb/config": "0.0.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"clean": "rimraf dist .turbo"
|
|
30
|
+
}
|
|
31
|
+
}
|