@shadow-dev/orm 1.0.0 → 1.0.2
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/core/Database.d.ts +6 -0
- package/dist/core/Database.js +28 -0
- package/dist/core/Model.d.ts +24 -0
- package/dist/core/Model.js +11 -0
- package/dist/core/Repository.d.ts +14 -0
- package/{src/core/Repository.ts → dist/core/Repository.js} +32 -40
- package/dist/core/index.js +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/utils/getNextId.d.ts +1 -0
- package/{src/utils/getNextId.ts → dist/utils/getNextId.js} +10 -11
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/syncSchema.d.ts +1 -0
- package/dist/utils/syncSchema.js +51 -0
- package/dist/utils/types.d.ts +3 -0
- package/dist/utils/types.js +2 -0
- package/package.json +3 -1
- package/.eslintrc.json +0 -21
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -37
- package/.github/dependabot.yml +0 -34
- package/.github/workflows/pr-checks.yml +0 -139
- package/.github/workflows/publish.yml +0 -31
- package/.github/workflows/release-please.yml +0 -23
- package/.github/workflows/setup-project.yml +0 -31
- package/.github/workflows/sonarcloud-analysis +0 -26
- package/eslint.config.mjs +0 -39
- package/jest.config.js +0 -5
- package/src/core/Database.ts +0 -24
- package/src/core/Model.ts +0 -18
- package/src/index.ts +0 -2
- package/src/utils/index.ts +0 -2
- package/src/utils/syncSchema.ts +0 -37
- package/tests/sample.test.ts +0 -5
- package/tsconfig.json +0 -13
- /package/{src/core/index.ts → dist/core/index.d.ts} +0 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import mysql from "mysql2/promise";
|
|
2
|
+
import { Model } from "./Model";
|
|
3
|
+
export declare function initDatabase(config: mysql.PoolOptions): void;
|
|
4
|
+
export declare function getPool(): mysql.Pool;
|
|
5
|
+
export declare function registerModel<T>(model: Model<T>): void;
|
|
6
|
+
export declare function getAllModels(): Map<string, Model<any>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initDatabase = initDatabase;
|
|
7
|
+
exports.getPool = getPool;
|
|
8
|
+
exports.registerModel = registerModel;
|
|
9
|
+
exports.getAllModels = getAllModels;
|
|
10
|
+
// Database.ts
|
|
11
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
12
|
+
let pool;
|
|
13
|
+
const modelRegistry = new Map();
|
|
14
|
+
function initDatabase(config) {
|
|
15
|
+
pool = promise_1.default.createPool(config);
|
|
16
|
+
}
|
|
17
|
+
function getPool() {
|
|
18
|
+
if (!pool)
|
|
19
|
+
throw new Error("Database not initialized");
|
|
20
|
+
return pool;
|
|
21
|
+
}
|
|
22
|
+
// @ts-expect-error wierd generic errors
|
|
23
|
+
function registerModel(model) {
|
|
24
|
+
modelRegistry.set(model.name, model);
|
|
25
|
+
}
|
|
26
|
+
function getAllModels() {
|
|
27
|
+
return modelRegistry;
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface BaseSchema {
|
|
2
|
+
id?: string;
|
|
3
|
+
data?: any;
|
|
4
|
+
createdAt?: Date;
|
|
5
|
+
}
|
|
6
|
+
export interface ForeignKeyDefinition {
|
|
7
|
+
column: string;
|
|
8
|
+
reference: string;
|
|
9
|
+
}
|
|
10
|
+
export type SimpleFieldType = "string" | "int" | "float" | "boolean" | "json" | "datetime";
|
|
11
|
+
export interface FieldOptions {
|
|
12
|
+
type: SimpleFieldType;
|
|
13
|
+
pk?: boolean;
|
|
14
|
+
required?: boolean;
|
|
15
|
+
default?: any;
|
|
16
|
+
}
|
|
17
|
+
export type SchemaValue = SimpleFieldType | FieldOptions;
|
|
18
|
+
export type FlexibleSchema<T> = Record<keyof T, SchemaValue>;
|
|
19
|
+
export declare class Model<T extends Partial<BaseSchema> = BaseSchema> {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly schema: FlexibleSchema<T>;
|
|
22
|
+
readonly foreignKeys: ForeignKeyDefinition[];
|
|
23
|
+
constructor(name: string, schema: FlexibleSchema<T>, foreignKeys?: ForeignKeyDefinition[]);
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Model = void 0;
|
|
4
|
+
class Model {
|
|
5
|
+
constructor(name, schema, foreignKeys = []) {
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.schema = schema;
|
|
8
|
+
this.foreignKeys = foreignKeys;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.Model = Model;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Model } from "./Model";
|
|
2
|
+
export declare class Repository<T extends object> {
|
|
3
|
+
readonly model: Model<T>;
|
|
4
|
+
constructor(model: Model<T>);
|
|
5
|
+
create(data: T): Promise<void>;
|
|
6
|
+
find(where?: Partial<T>): Promise<T[]>;
|
|
7
|
+
findOne(where: Partial<T>): Promise<T | null>;
|
|
8
|
+
update(where: Partial<T>, data: Partial<T>): Promise<void>;
|
|
9
|
+
delete(where: Partial<T>): Promise<void>;
|
|
10
|
+
count(where?: Partial<T>): Promise<number>;
|
|
11
|
+
exists(where: Partial<T>): Promise<boolean>;
|
|
12
|
+
private normalizeValue;
|
|
13
|
+
private buildWhereClause;
|
|
14
|
+
}
|
|
@@ -1,63 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Repository = void 0;
|
|
1
4
|
// Repository.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
async create(data: T): Promise<void> {
|
|
5
|
+
const Database_1 = require("./Database");
|
|
6
|
+
class Repository {
|
|
7
|
+
constructor(model) {
|
|
8
|
+
this.model = model;
|
|
9
|
+
}
|
|
10
|
+
async create(data) {
|
|
9
11
|
const keys = Object.keys(data);
|
|
10
12
|
const sql = `INSERT INTO \`${this.model.name}\` (${keys.join(",")}) VALUES (${keys.map(() => "?").join(",")})`;
|
|
11
|
-
const values = keys.map((key) => this.normalizeValue(
|
|
12
|
-
|
|
13
|
-
await getPool().execute(sql, values);
|
|
13
|
+
const values = keys.map((key) => this.normalizeValue(data[key]));
|
|
14
|
+
await (0, Database_1.getPool)().execute(sql, values);
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
async find(where: Partial<T> = {}): Promise<T[]> {
|
|
16
|
+
async find(where = {}) {
|
|
18
17
|
const { sql, params } = this.buildWhereClause(where);
|
|
19
18
|
const query = `SELECT * FROM \`${this.model.name}\` ${sql}`;
|
|
20
|
-
const [rows] = await getPool().execute(query, params.map(this.normalizeValue));
|
|
21
|
-
return rows
|
|
19
|
+
const [rows] = await (0, Database_1.getPool)().execute(query, params.map(this.normalizeValue));
|
|
20
|
+
return rows;
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
async findOne(where: Partial<T>): Promise<T | null> {
|
|
22
|
+
async findOne(where) {
|
|
25
23
|
const { sql, params } = this.buildWhereClause(where);
|
|
26
24
|
const query = `SELECT * FROM \`${this.model.name}\` ${sql} LIMIT 1`;
|
|
27
|
-
const [rows] = await getPool().execute(query, params.map(this.normalizeValue));
|
|
28
|
-
const results = rows
|
|
25
|
+
const [rows] = await (0, Database_1.getPool)().execute(query, params.map(this.normalizeValue));
|
|
26
|
+
const results = rows;
|
|
29
27
|
return results.length > 0 ? results[0] : null;
|
|
30
28
|
}
|
|
31
|
-
|
|
32
|
-
async update(where: Partial<T>, data: Partial<T>): Promise<void> {
|
|
29
|
+
async update(where, data) {
|
|
33
30
|
const setKeys = Object.keys(data);
|
|
34
31
|
const setClause = setKeys.map(k => `${k} = ?`).join(", ");
|
|
35
|
-
const setValues = setKeys.map(k => this.normalizeValue(
|
|
36
|
-
|
|
32
|
+
const setValues = setKeys.map(k => this.normalizeValue(data[k]));
|
|
37
33
|
const { sql: whereClause, params: whereValues } = this.buildWhereClause(where);
|
|
38
34
|
const query = `UPDATE \`${this.model.name}\` SET ${setClause} ${whereClause}`;
|
|
39
|
-
await getPool().execute(query, [...setValues, ...whereValues.map(this.normalizeValue)]);
|
|
35
|
+
await (0, Database_1.getPool)().execute(query, [...setValues, ...whereValues.map(this.normalizeValue)]);
|
|
40
36
|
}
|
|
41
|
-
|
|
42
|
-
async delete(where: Partial<T>): Promise<void> {
|
|
37
|
+
async delete(where) {
|
|
43
38
|
const { sql, params } = this.buildWhereClause(where);
|
|
44
39
|
const query = `DELETE FROM \`${this.model.name}\` ${sql}`;
|
|
45
|
-
await getPool().execute(query, params.map(this.normalizeValue));
|
|
40
|
+
await (0, Database_1.getPool)().execute(query, params.map(this.normalizeValue));
|
|
46
41
|
}
|
|
47
|
-
|
|
48
|
-
async count(where: Partial<T> = {}): Promise<number> {
|
|
42
|
+
async count(where = {}) {
|
|
49
43
|
const { sql, params } = this.buildWhereClause(where);
|
|
50
44
|
const query = `SELECT COUNT(*) as count FROM \`${this.model.name}\` ${sql}`;
|
|
51
|
-
const [rows] = await getPool().execute(query, params.map(this.normalizeValue));
|
|
52
|
-
return
|
|
45
|
+
const [rows] = await (0, Database_1.getPool)().execute(query, params.map(this.normalizeValue));
|
|
46
|
+
return rows[0].count || 0;
|
|
53
47
|
}
|
|
54
|
-
|
|
55
|
-
async exists(where: Partial<T>): Promise<boolean> {
|
|
48
|
+
async exists(where) {
|
|
56
49
|
const count = await this.count(where);
|
|
57
50
|
return count > 0;
|
|
58
51
|
}
|
|
59
|
-
|
|
60
|
-
private normalizeValue(value: any): any {
|
|
52
|
+
normalizeValue(value) {
|
|
61
53
|
if (value instanceof Date) {
|
|
62
54
|
return value.toISOString().slice(0, 19).replace("T", " ");
|
|
63
55
|
}
|
|
@@ -66,16 +58,16 @@ export class Repository<T extends object> {
|
|
|
66
58
|
}
|
|
67
59
|
return value ?? null;
|
|
68
60
|
}
|
|
69
|
-
|
|
70
|
-
private buildWhereClause(where: Partial<T>): { sql: string; params: any[] } {
|
|
61
|
+
buildWhereClause(where) {
|
|
71
62
|
const keys = Object.keys(where);
|
|
72
|
-
if (keys.length === 0)
|
|
73
|
-
|
|
63
|
+
if (keys.length === 0)
|
|
64
|
+
return { sql: "", params: [] };
|
|
74
65
|
const conditions = keys.map(k => `${k} = ?`).join(" AND ");
|
|
75
|
-
const values = keys.map(k =>
|
|
66
|
+
const values = keys.map(k => where[k]);
|
|
76
67
|
return {
|
|
77
68
|
sql: `WHERE ${conditions}`,
|
|
78
69
|
params: values,
|
|
79
70
|
};
|
|
80
71
|
}
|
|
81
72
|
}
|
|
73
|
+
exports.Repository = Repository;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./Model"), exports);
|
|
18
|
+
__exportStar(require("./Repository"), exports);
|
|
19
|
+
__exportStar(require("./Database"), exports);
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./core"), exports);
|
|
18
|
+
__exportStar(require("./utils"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getNextId(prefix: string): Promise<string>;
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getNextId = getNextId;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
async function getNextId(prefix) {
|
|
6
|
+
const pool = (0, core_1.getPool)();
|
|
6
7
|
await pool.execute(`
|
|
7
8
|
CREATE TABLE IF NOT EXISTS _id_counters (
|
|
8
9
|
prefix VARCHAR(255) PRIMARY KEY,
|
|
9
10
|
count INT NOT NULL
|
|
10
11
|
)
|
|
11
12
|
`);
|
|
12
|
-
|
|
13
13
|
const [rows] = await pool.query(`SELECT count FROM _id_counters WHERE prefix = ?`, [prefix]);
|
|
14
14
|
let count = 1;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
count = (rows as any)[0].count + 1;
|
|
15
|
+
if (rows.length > 0) {
|
|
16
|
+
count = rows[0].count + 1;
|
|
18
17
|
await pool.execute(`UPDATE _id_counters SET count = ? WHERE prefix = ?`, [count, prefix]);
|
|
19
|
-
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
20
|
await pool.execute(`INSERT INTO _id_counters (prefix, count) VALUES (?, ?)`, [prefix, count]);
|
|
21
21
|
}
|
|
22
|
-
|
|
23
22
|
return `${prefix}-${String(count).padStart(3, "0")}`;
|
|
24
23
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./getNextId"), exports);
|
|
18
|
+
__exportStar(require("./syncSchema"), exports);
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function syncSchema(): Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncSchema = syncSchema;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
function normalizeField(value) {
|
|
6
|
+
if (typeof value === "string")
|
|
7
|
+
return { type: value };
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function formatDefault(value) {
|
|
11
|
+
if (typeof value === "string")
|
|
12
|
+
return `'${value}'`;
|
|
13
|
+
if (typeof value === "boolean")
|
|
14
|
+
return value ? "TRUE" : "FALSE";
|
|
15
|
+
if (value === null || value === undefined)
|
|
16
|
+
return "NULL";
|
|
17
|
+
return value.toString();
|
|
18
|
+
}
|
|
19
|
+
function mapType(type) {
|
|
20
|
+
switch (type.toLowerCase()) {
|
|
21
|
+
case "string": return "VARCHAR(255)";
|
|
22
|
+
case "json": return "JSON";
|
|
23
|
+
case "datetime": return "DATETIME";
|
|
24
|
+
case "number": return "INT";
|
|
25
|
+
case "float": return "FLOAT";
|
|
26
|
+
case "boolean": return "BOOLEAN";
|
|
27
|
+
default: return type;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function syncSchema() {
|
|
31
|
+
const models = (0, core_1.getAllModels)();
|
|
32
|
+
const pool = (0, core_1.getPool)();
|
|
33
|
+
for (const [name, model] of models.entries()) {
|
|
34
|
+
const columns = [];
|
|
35
|
+
for (const [key, value] of Object.entries(model.schema)) {
|
|
36
|
+
const { type, pk, default: def, required } = normalizeField(value);
|
|
37
|
+
let col = `\`${key}\` ${mapType(type)}`;
|
|
38
|
+
if (required || pk)
|
|
39
|
+
col += " NOT NULL";
|
|
40
|
+
if (pk)
|
|
41
|
+
col += " PRIMARY KEY";
|
|
42
|
+
if (def !== undefined)
|
|
43
|
+
col += ` DEFAULT ${formatDefault(def)}`;
|
|
44
|
+
columns.push(col);
|
|
45
|
+
}
|
|
46
|
+
const fks = model.foreignKeys.map(fk => `FOREIGN KEY (\`${fk.column}\`) REFERENCES ${fk.reference}`);
|
|
47
|
+
const sql = `CREATE TABLE IF NOT EXISTS \`${name}\` (\n ${[...columns, ...fks].join(',\n ')}\n);`;
|
|
48
|
+
await pool.execute(sql);
|
|
49
|
+
}
|
|
50
|
+
console.log("✅ Schema synchronized.");
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shadow-dev/orm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Lightweight dynamic MySQL ORM designed for ShadowCore and modular apps.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": ["dist"],
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
10
|
"import": "./dist/index.js",
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
15
|
"scripts": {
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
15
17
|
"dev": "ts-node src/index.ts",
|
|
16
18
|
"build": "tsc",
|
|
17
19
|
"lint": "eslint . --ext .ts",
|
package/.eslintrc.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": true,
|
|
3
|
-
"parser": "@typescript-eslint/parser",
|
|
4
|
-
"plugins": ["@typescript-eslint"],
|
|
5
|
-
"extends": [
|
|
6
|
-
"eslint:recommended",
|
|
7
|
-
"plugin:@typescript-eslint/recommended"
|
|
8
|
-
],
|
|
9
|
-
"env": {
|
|
10
|
-
"node": true,
|
|
11
|
-
"es2021": true
|
|
12
|
-
},
|
|
13
|
-
"parserOptions": {
|
|
14
|
-
"ecmaVersion": 2021,
|
|
15
|
-
"sourceType": "module"
|
|
16
|
-
},
|
|
17
|
-
"rules": {
|
|
18
|
-
"@typescript-eslint/no-unused-vars": ["warn"],
|
|
19
|
-
"@typescript-eslint/no-explicit-any": "off"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
## 📝 Description
|
|
2
|
-
<!-- Describe your changes in detail. Explain the problem and how your PR fixes it. -->
|
|
3
|
-
|
|
4
|
-
## 🔍 Related Issues
|
|
5
|
-
<!-- Link any relevant issues (e.g., "Closes #123") -->
|
|
6
|
-
|
|
7
|
-
## 🚀 Changes Made
|
|
8
|
-
- [ ] Bug fix 🐛
|
|
9
|
-
- [ ] New feature ✨
|
|
10
|
-
- [ ] Code refactor 🔧
|
|
11
|
-
- [ ] Documentation update 📖
|
|
12
|
-
- [ ] Security improvement 🔒
|
|
13
|
-
- [ ] Other (please specify): ____________
|
|
14
|
-
|
|
15
|
-
## ✅ Testing Steps
|
|
16
|
-
<!-- Provide instructions for testing your changes. Include commands, expected behavior, and test cases if applicable. -->
|
|
17
|
-
1.
|
|
18
|
-
2.
|
|
19
|
-
3.
|
|
20
|
-
|
|
21
|
-
## 🔒 Security Considerations
|
|
22
|
-
<!-- Any security implications? Dependencies updated? New permissions required? -->
|
|
23
|
-
|
|
24
|
-
## 📸 Screenshots / Logs (if applicable)
|
|
25
|
-
<!-- Add screenshots or logs if they help understand the change. -->
|
|
26
|
-
|
|
27
|
-
## ⏳ Checklist
|
|
28
|
-
- [ ] My code follows the project coding style.
|
|
29
|
-
- [ ] I have run tests to verify my changes.
|
|
30
|
-
- [ ] I have updated the documentation if needed.
|
|
31
|
-
- [ ] My changes do not introduce new vulnerabilities.
|
|
32
|
-
- [ ] This PR is ready for review.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
### 🚀 Additional Notes
|
|
37
|
-
<!-- Anything else reviewers should know? -->
|
package/.github/dependabot.yml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
-
# package ecosystems to update and where the package manifests are located.
|
|
3
|
-
# Please see the documentation for all configuration options:
|
|
4
|
-
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
-
|
|
6
|
-
version: 2
|
|
7
|
-
updates:
|
|
8
|
-
# 📦 Keep npm dependencies up to date
|
|
9
|
-
- package-ecosystem: "npm"
|
|
10
|
-
directory: "/" # Root directory (where package.json is)
|
|
11
|
-
schedule:
|
|
12
|
-
interval: "daily"
|
|
13
|
-
open-pull-requests-limit: 5
|
|
14
|
-
versioning-strategy: increase
|
|
15
|
-
labels:
|
|
16
|
-
- "dependencies"
|
|
17
|
-
- "npm"
|
|
18
|
-
reviewers:
|
|
19
|
-
- "Shadows-Development" # Add yourself or contributors as reviewers
|
|
20
|
-
commit-message:
|
|
21
|
-
prefix: "⬆️ Bump"
|
|
22
|
-
include: "scope" # Includes dependency name in commit message
|
|
23
|
-
|
|
24
|
-
# 🔒 Check for security updates in GitHub Actions (workflow dependencies)
|
|
25
|
-
- package-ecosystem: "github-actions"
|
|
26
|
-
directory: "/" # Root directory (where workflows are)
|
|
27
|
-
schedule:
|
|
28
|
-
interval: "daily"
|
|
29
|
-
labels:
|
|
30
|
-
- "security"
|
|
31
|
-
- "github-actions"
|
|
32
|
-
commit-message:
|
|
33
|
-
prefix: "🔄 Update"
|
|
34
|
-
include: "scope"
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
name: PR Checks
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request: # Runs on every commit in an open PR
|
|
5
|
-
|
|
6
|
-
jobs:
|
|
7
|
-
build:
|
|
8
|
-
name: 🏗 Build & Type Check
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout repository
|
|
12
|
-
uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- name: Setup Node.js
|
|
15
|
-
uses: actions/setup-node@v4
|
|
16
|
-
with:
|
|
17
|
-
node-version: 20
|
|
18
|
-
cache: 'npm' # Speeds up installs
|
|
19
|
-
|
|
20
|
-
- name: Restore dependency cache
|
|
21
|
-
uses: actions/cache@v4
|
|
22
|
-
with:
|
|
23
|
-
path: ~/.npm
|
|
24
|
-
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
25
|
-
restore-keys: |
|
|
26
|
-
npm-${{ runner.os }}-
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: |
|
|
30
|
-
if [ -f package-lock.json ]; then
|
|
31
|
-
npm ci
|
|
32
|
-
else
|
|
33
|
-
npm install
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
- name: TypeScript type checking
|
|
37
|
-
run: npm run type-check
|
|
38
|
-
|
|
39
|
-
- name: Build project
|
|
40
|
-
run: npm run build
|
|
41
|
-
|
|
42
|
-
lint:
|
|
43
|
-
name: 🎨 Lint Code
|
|
44
|
-
runs-on: ubuntu-latest
|
|
45
|
-
needs: build # Runs only if "build" passes
|
|
46
|
-
steps:
|
|
47
|
-
- name: Checkout repository
|
|
48
|
-
uses: actions/checkout@v4
|
|
49
|
-
|
|
50
|
-
- name: Setup Node.js
|
|
51
|
-
uses: actions/setup-node@v4
|
|
52
|
-
with:
|
|
53
|
-
node-version: 20
|
|
54
|
-
cache: 'npm'
|
|
55
|
-
|
|
56
|
-
- name: Restore dependency cache
|
|
57
|
-
uses: actions/cache@v4
|
|
58
|
-
with:
|
|
59
|
-
path: ~/.npm
|
|
60
|
-
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
61
|
-
restore-keys: |
|
|
62
|
-
npm-${{ runner.os }}-
|
|
63
|
-
|
|
64
|
-
- name: Install dependencies
|
|
65
|
-
run: |
|
|
66
|
-
if [ -f package-lock.json ]; then
|
|
67
|
-
npm ci
|
|
68
|
-
else
|
|
69
|
-
npm install
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
- name: Run ESLint
|
|
73
|
-
run: npm run lint
|
|
74
|
-
|
|
75
|
-
security:
|
|
76
|
-
name: 🔒 Security Audit
|
|
77
|
-
runs-on: ubuntu-latest
|
|
78
|
-
needs: lint # Runs only if "lint" passes
|
|
79
|
-
steps:
|
|
80
|
-
- name: Checkout repository
|
|
81
|
-
uses: actions/checkout@v4
|
|
82
|
-
|
|
83
|
-
- name: Setup Node.js
|
|
84
|
-
uses: actions/setup-node@v4
|
|
85
|
-
with:
|
|
86
|
-
node-version: 20
|
|
87
|
-
cache: 'npm'
|
|
88
|
-
|
|
89
|
-
- name: Restore dependency cache
|
|
90
|
-
uses: actions/cache@v4
|
|
91
|
-
with:
|
|
92
|
-
path: ~/.npm
|
|
93
|
-
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
94
|
-
restore-keys: |
|
|
95
|
-
npm-${{ runner.os }}-
|
|
96
|
-
|
|
97
|
-
- name: Install dependencies
|
|
98
|
-
run: |
|
|
99
|
-
if [ -f package-lock.json ]; then
|
|
100
|
-
npm ci
|
|
101
|
-
else
|
|
102
|
-
npm install
|
|
103
|
-
fi
|
|
104
|
-
|
|
105
|
-
- name: Run npm audit
|
|
106
|
-
run: npm audit --audit-level=high || exit 1
|
|
107
|
-
|
|
108
|
-
tests:
|
|
109
|
-
name: 🧪 Run Tests
|
|
110
|
-
runs-on: ubuntu-latest
|
|
111
|
-
needs: security # Runs only if "security" passes
|
|
112
|
-
steps:
|
|
113
|
-
- name: Checkout repository
|
|
114
|
-
uses: actions/checkout@v4
|
|
115
|
-
|
|
116
|
-
- name: Setup Node.js
|
|
117
|
-
uses: actions/setup-node@v4
|
|
118
|
-
with:
|
|
119
|
-
node-version: 20
|
|
120
|
-
cache: 'npm'
|
|
121
|
-
|
|
122
|
-
- name: Restore dependency cache
|
|
123
|
-
uses: actions/cache@v4
|
|
124
|
-
with:
|
|
125
|
-
path: ~/.npm
|
|
126
|
-
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
127
|
-
restore-keys: |
|
|
128
|
-
npm-${{ runner.os }}-
|
|
129
|
-
|
|
130
|
-
- name: Install dependencies
|
|
131
|
-
run: |
|
|
132
|
-
if [ -f package-lock.json ]; then
|
|
133
|
-
npm ci
|
|
134
|
-
else
|
|
135
|
-
npm install
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
- name: Run tests
|
|
139
|
-
run: npm test
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*" # Triggers when you push a tag like "v1.0.0"
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
publish:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- name: Checkout Repository
|
|
14
|
-
uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- name: Setup Node.js
|
|
17
|
-
uses: actions/setup-node@v4
|
|
18
|
-
with:
|
|
19
|
-
node-version: 18
|
|
20
|
-
registry-url: "https://registry.npmjs.org/"
|
|
21
|
-
|
|
22
|
-
- name: Install Dependencies
|
|
23
|
-
run: npm install
|
|
24
|
-
|
|
25
|
-
- name: Build Package
|
|
26
|
-
run: npm run build # Skip if no build step
|
|
27
|
-
|
|
28
|
-
- name: Publish to npm
|
|
29
|
-
run: npm publish --access public
|
|
30
|
-
env:
|
|
31
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: Release Please
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
pull-requests: write
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
release:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
steps:
|
|
17
|
-
- name: Checkout Repo
|
|
18
|
-
uses: actions/checkout@v4
|
|
19
|
-
|
|
20
|
-
- name: Run Release Please
|
|
21
|
-
uses: googleapis/release-please-action@v4
|
|
22
|
-
with:
|
|
23
|
-
release-type: node
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Setup Project
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
|
|
6
|
-
permissions:
|
|
7
|
-
contents: write
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
setup:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- name: Checkout code
|
|
14
|
-
uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- name: Setup Node.js
|
|
17
|
-
uses: actions/setup-node@v4
|
|
18
|
-
with:
|
|
19
|
-
node-version: 18
|
|
20
|
-
|
|
21
|
-
- name: Run setup script
|
|
22
|
-
run: node scripts/setup.js
|
|
23
|
-
|
|
24
|
-
- name: Push updated files
|
|
25
|
-
run: |
|
|
26
|
-
git config user.name "ShadowBot"
|
|
27
|
-
git config user.email "bot@shadowdev.local"
|
|
28
|
-
git remote set-url origin https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/${{ github.repository }}
|
|
29
|
-
git add .
|
|
30
|
-
git commit -m "chore: initialize project metadata from setup script" || echo "No changes"
|
|
31
|
-
git push
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
name: SonarCloud Analysis
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
pull_request:
|
|
7
|
-
branches:
|
|
8
|
-
- main
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
sonarcloud:
|
|
12
|
-
name: SonarCloud Scan
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@v2
|
|
18
|
-
|
|
19
|
-
- name: Set up SonarCloud
|
|
20
|
-
uses: SonarSource/sonarcloud-github-action@v1.1
|
|
21
|
-
|
|
22
|
-
- name: Run SonarCloud analysis
|
|
23
|
-
env:
|
|
24
|
-
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
25
|
-
run: |
|
|
26
|
-
sonar-scanner
|
package/eslint.config.mjs
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import js from "@eslint/js";
|
|
2
|
-
import globals from "globals";
|
|
3
|
-
import tseslint from "typescript-eslint";
|
|
4
|
-
import json from "@eslint/json";
|
|
5
|
-
import { defineConfig, globalIgnores } from "eslint/config";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// export default defineConfig([
|
|
9
|
-
// { files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"] },
|
|
10
|
-
// { files: ["**/*.js"], languageOptions: { sourceType: "script" } },
|
|
11
|
-
// { files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: {...globals.browser, ...globals.node} } },
|
|
12
|
-
// tseslint.configs.recommended,
|
|
13
|
-
// ]);
|
|
14
|
-
export default defineConfig([
|
|
15
|
-
{ files: ["**/*.{js,mjs,cjs,ts}"] },
|
|
16
|
-
{
|
|
17
|
-
files: ["**/*.{js,mjs,cjs,ts}"],
|
|
18
|
-
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
files: ["**/*.{js,mjs,cjs,ts}"],
|
|
22
|
-
plugins: { js },
|
|
23
|
-
extends: ["js/recommended"],
|
|
24
|
-
},
|
|
25
|
-
{ files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] },
|
|
26
|
-
tseslint.configs.recommended,
|
|
27
|
-
{
|
|
28
|
-
rules: {
|
|
29
|
-
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
30
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
31
|
-
"@typescript-eslint/no-require-imports": "off",
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
globalIgnores([
|
|
35
|
-
"node_modules/*", // ignore its content
|
|
36
|
-
"dist/*",
|
|
37
|
-
"package-lock.json",
|
|
38
|
-
]),
|
|
39
|
-
]);
|
package/jest.config.js
DELETED
package/src/core/Database.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// Database.ts
|
|
2
|
-
import mysql from "mysql2/promise";
|
|
3
|
-
import { Model } from "./Model";
|
|
4
|
-
|
|
5
|
-
let pool: mysql.Pool;
|
|
6
|
-
const modelRegistry = new Map<string, Model<any>>();
|
|
7
|
-
|
|
8
|
-
export function initDatabase(config: mysql.PoolOptions) {
|
|
9
|
-
pool = mysql.createPool(config);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getPool() {
|
|
13
|
-
if (!pool) throw new Error("Database not initialized");
|
|
14
|
-
return pool;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// @ts-expect-error wierd generic errors
|
|
18
|
-
export function registerModel<T>(model: Model<T>) {
|
|
19
|
-
modelRegistry.set(model.name, model);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getAllModels() {
|
|
23
|
-
return modelRegistry;
|
|
24
|
-
}
|
package/src/core/Model.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface BaseSchema {
|
|
2
|
-
id: string;
|
|
3
|
-
data?: any;
|
|
4
|
-
createdAt: Date;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface ForeignKeyDefinition {
|
|
8
|
-
column: string;
|
|
9
|
-
reference: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class Model<T extends Partial<BaseSchema> = BaseSchema> {
|
|
13
|
-
constructor(
|
|
14
|
-
public readonly name: string,
|
|
15
|
-
public readonly schema: Record<keyof T, string>,
|
|
16
|
-
public readonly foreignKeys: ForeignKeyDefinition[] = []
|
|
17
|
-
) {}
|
|
18
|
-
}
|
package/src/index.ts
DELETED
package/src/utils/index.ts
DELETED
package/src/utils/syncSchema.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {getAllModels, getPool} from '../core'
|
|
2
|
-
|
|
3
|
-
export async function syncSchema() {
|
|
4
|
-
const models = getAllModels();
|
|
5
|
-
const pool = getPool();
|
|
6
|
-
|
|
7
|
-
for (const [name, model] of models.entries()) {
|
|
8
|
-
const columns: string[] = [];
|
|
9
|
-
const foreignKeys: string[] = [];
|
|
10
|
-
|
|
11
|
-
for (const [key, type] of Object.entries(model.schema)) {
|
|
12
|
-
columns.push(`\`${key}\` ${mapType(type)}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
for (const fk of model.foreignKeys) {
|
|
16
|
-
foreignKeys.push(`FOREIGN KEY (\`${fk.column}\`) REFERENCES ${fk.reference}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const columnDefs = [...columns, ...foreignKeys].join(",\n ");
|
|
20
|
-
const sql = `CREATE TABLE IF NOT EXISTS \`${name}\` (\n ${columnDefs}\n);`;
|
|
21
|
-
|
|
22
|
-
await pool.execute(sql);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log("✅ Schema synchronized.");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function mapType(type: string): string {
|
|
29
|
-
switch (type.toLowerCase()) {
|
|
30
|
-
case "string": return "VARCHAR(255)";
|
|
31
|
-
case "json": return "JSON";
|
|
32
|
-
case "datetime": return "DATETIME";
|
|
33
|
-
case "number": return "INT";
|
|
34
|
-
case "boolean": return "BOOLEAN";
|
|
35
|
-
default: return type; // fallback for raw SQL types if provided
|
|
36
|
-
}
|
|
37
|
-
}
|
package/tests/sample.test.ts
DELETED
package/tsconfig.json
DELETED
|
File without changes
|