@hasna/microservices 0.0.15 → 0.0.16
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/README.md +25 -163
- package/bin/index.js +4451 -3189
- package/bin/mcp.js +5312 -4029
- package/dist/index.js +3806 -3153
- package/microservices/microservice-ads/package.json +1 -0
- package/microservices/microservice-ads/src/db/database.ts +20 -22
- package/microservices/microservice-analytics/package.json +1 -0
- package/microservices/microservice-analytics/src/db/database.ts +20 -22
- package/microservices/microservice-assets/package.json +1 -0
- package/microservices/microservice-assets/src/db/database.ts +20 -22
- package/microservices/microservice-bookkeeping/package.json +1 -0
- package/microservices/microservice-bookkeeping/src/db/database.ts +20 -22
- package/microservices/microservice-calendar/package.json +1 -0
- package/microservices/microservice-calendar/src/db/database.ts +20 -11
- package/microservices/microservice-company/package.json +1 -0
- package/microservices/microservice-company/src/db/database.ts +20 -22
- package/microservices/microservice-compliance/package.json +1 -0
- package/microservices/microservice-compliance/src/db/database.ts +20 -22
- package/microservices/microservice-contacts/package.json +1 -0
- package/microservices/microservice-contacts/src/db/database.ts +20 -22
- package/microservices/microservice-contracts/package.json +1 -0
- package/microservices/microservice-contracts/src/db/database.ts +20 -22
- package/microservices/microservice-crm/package.json +1 -0
- package/microservices/microservice-crm/src/db/database.ts +20 -11
- package/microservices/microservice-documents/package.json +1 -0
- package/microservices/microservice-documents/src/db/database.ts +20 -11
- package/microservices/microservice-domains/package.json +1 -0
- package/microservices/microservice-domains/src/db/database.ts +20 -22
- package/microservices/microservice-expenses/package.json +1 -0
- package/microservices/microservice-expenses/src/db/database.ts +20 -11
- package/microservices/microservice-habits/package.json +1 -0
- package/microservices/microservice-habits/src/db/database.ts +20 -22
- package/microservices/microservice-health/package.json +1 -0
- package/microservices/microservice-health/src/db/database.ts +20 -22
- package/microservices/microservice-hiring/package.json +1 -0
- package/microservices/microservice-hiring/src/db/database.ts +20 -22
- package/microservices/microservice-inventory/package.json +1 -0
- package/microservices/microservice-inventory/src/db/database.ts +20 -11
- package/microservices/microservice-invoices/package.json +1 -0
- package/microservices/microservice-invoices/src/db/database.ts +20 -11
- package/microservices/microservice-leads/package.json +1 -0
- package/microservices/microservice-leads/src/db/database.ts +20 -22
- package/microservices/microservice-notes/package.json +1 -0
- package/microservices/microservice-notes/src/db/database.ts +20 -22
- package/microservices/microservice-notifications/package.json +1 -0
- package/microservices/microservice-notifications/src/db/database.ts +20 -22
- package/microservices/microservice-payments/package.json +1 -0
- package/microservices/microservice-payments/src/db/database.ts +20 -22
- package/microservices/microservice-payroll/package.json +1 -0
- package/microservices/microservice-payroll/src/db/database.ts +20 -22
- package/microservices/microservice-products/package.json +1 -0
- package/microservices/microservice-products/src/db/database.ts +20 -22
- package/microservices/microservice-projects/package.json +1 -0
- package/microservices/microservice-projects/src/db/database.ts +20 -22
- package/microservices/microservice-proposals/package.json +1 -0
- package/microservices/microservice-proposals/src/db/database.ts +20 -22
- package/microservices/microservice-reading/package.json +1 -0
- package/microservices/microservice-reading/src/db/database.ts +20 -22
- package/microservices/microservice-shipping/package.json +1 -0
- package/microservices/microservice-shipping/src/db/database.ts +20 -22
- package/microservices/microservice-social/package.json +1 -0
- package/microservices/microservice-social/src/db/database.ts +20 -22
- package/microservices/microservice-subscriptions/package.json +1 -0
- package/microservices/microservice-subscriptions/src/db/database.ts +20 -22
- package/microservices/microservice-timesheets/package.json +1 -0
- package/microservices/microservice-timesheets/src/db/database.ts +20 -11
- package/microservices/microservice-transcriber/package.json +1 -0
- package/microservices/microservice-transcriber/src/db/database.ts +20 -11
- package/microservices/microservice-travel/package.json +1 -0
- package/microservices/microservice-travel/src/db/database.ts +20 -22
- package/microservices/microservice-wiki/package.json +1 -0
- package/microservices/microservice-wiki/src/db/database.ts +20 -22
- package/package.json +2 -2
- package/microservices/microservice-invoices/dashboard/dist/assets/index-Bngq7FNM.css +0 -1
- package/microservices/microservice-invoices/dashboard/dist/assets/index-aHW4ARZR.js +0 -124
- package/microservices/microservice-invoices/dashboard/dist/index.html +0 -13
|
@@ -2,53 +2,52 @@
|
|
|
2
2
|
* Database connection for microservice-social
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
return join(
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-social", "data.db");
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
// Check for .microservices in current or parent directories
|
|
19
19
|
let dir = resolve(process.cwd());
|
|
20
20
|
while (true) {
|
|
21
|
-
const candidate = join(dir, ".microservices", "microservice-social", "data.db");
|
|
22
21
|
const msDir = join(dir, ".microservices");
|
|
23
|
-
if (existsSync(msDir)) return
|
|
22
|
+
if (existsSync(msDir)) return join(msDir, "microservice-social", "data.db");
|
|
24
23
|
const parent = dirname(dir);
|
|
25
24
|
if (parent === dir) break;
|
|
26
25
|
dir = parent;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
// Global fallback
|
|
30
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true });
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
38
34
|
}
|
|
35
|
+
return join(newDir, "microservice-social", "data.db");
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
export function getDatabase(): Database {
|
|
42
39
|
if (_db) return _db;
|
|
43
40
|
|
|
44
41
|
const dbPath = getDbPath();
|
|
45
|
-
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
_db
|
|
49
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
50
50
|
|
|
51
|
-
// Create migrations table
|
|
52
51
|
_db.exec(`
|
|
53
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
54
53
|
id INTEGER PRIMARY KEY,
|
|
@@ -57,7 +56,6 @@ export function getDatabase(): Database {
|
|
|
57
56
|
)
|
|
58
57
|
`);
|
|
59
58
|
|
|
60
|
-
// Apply pending migrations
|
|
61
59
|
const applied = _db
|
|
62
60
|
.query("SELECT id FROM _migrations ORDER BY id")
|
|
63
61
|
.all() as { id: number }[];
|
|
@@ -2,53 +2,52 @@
|
|
|
2
2
|
* Database connection for microservice-subscriptions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
return join(
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-subscriptions", "data.db");
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
// Check for .microservices in current or parent directories
|
|
19
19
|
let dir = resolve(process.cwd());
|
|
20
20
|
while (true) {
|
|
21
|
-
const candidate = join(dir, ".microservices", "microservice-subscriptions", "data.db");
|
|
22
21
|
const msDir = join(dir, ".microservices");
|
|
23
|
-
if (existsSync(msDir)) return
|
|
22
|
+
if (existsSync(msDir)) return join(msDir, "microservice-subscriptions", "data.db");
|
|
24
23
|
const parent = dirname(dir);
|
|
25
24
|
if (parent === dir) break;
|
|
26
25
|
dir = parent;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
// Global fallback
|
|
30
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true });
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
38
34
|
}
|
|
35
|
+
return join(newDir, "microservice-subscriptions", "data.db");
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
export function getDatabase(): Database {
|
|
42
39
|
if (_db) return _db;
|
|
43
40
|
|
|
44
41
|
const dbPath = getDbPath();
|
|
45
|
-
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
_db
|
|
49
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
50
50
|
|
|
51
|
-
// Create migrations table
|
|
52
51
|
_db.exec(`
|
|
53
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
54
53
|
id INTEGER PRIMARY KEY,
|
|
@@ -57,7 +56,6 @@ export function getDatabase(): Database {
|
|
|
57
56
|
)
|
|
58
57
|
`);
|
|
59
58
|
|
|
60
|
-
// Apply pending migrations
|
|
61
59
|
const applied = _db
|
|
62
60
|
.query("SELECT id FROM _migrations ORDER BY id")
|
|
63
61
|
.all() as { id: number }[];
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
* Database connection for microservice-timesheets
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-timesheets", "data.db");
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
let dir = resolve(process.cwd());
|
|
@@ -24,21 +26,27 @@ function getDbPath(): string {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
27
|
-
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
return join(newDir, "microservice-timesheets", "data.db");
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
export function getDatabase(): Database {
|
|
31
39
|
if (_db) return _db;
|
|
32
40
|
|
|
33
41
|
const dbPath = getDbPath();
|
|
34
|
-
const
|
|
35
|
-
if (!existsSync(
|
|
36
|
-
mkdirSync(
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
|
|
40
|
-
_db
|
|
41
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
42
50
|
|
|
43
51
|
_db.exec(`
|
|
44
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
@@ -55,6 +63,7 @@ export function getDatabase(): Database {
|
|
|
55
63
|
|
|
56
64
|
for (const migration of MIGRATIONS) {
|
|
57
65
|
if (appliedIds.has(migration.id)) continue;
|
|
66
|
+
|
|
58
67
|
_db.exec("BEGIN");
|
|
59
68
|
try {
|
|
60
69
|
_db.exec(migration.sql);
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
* Database connection for microservice-transcriber
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-transcriber", "data.db");
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
let dir = resolve(process.cwd());
|
|
@@ -24,21 +26,27 @@ function getDbPath(): string {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
27
|
-
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
return join(newDir, "microservice-transcriber", "data.db");
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
export function getDatabase(): Database {
|
|
31
39
|
if (_db) return _db;
|
|
32
40
|
|
|
33
41
|
const dbPath = getDbPath();
|
|
34
|
-
const
|
|
35
|
-
if (!existsSync(
|
|
36
|
-
mkdirSync(
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
|
|
40
|
-
_db
|
|
41
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
42
50
|
|
|
43
51
|
_db.exec(`
|
|
44
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
@@ -55,6 +63,7 @@ export function getDatabase(): Database {
|
|
|
55
63
|
|
|
56
64
|
for (const migration of MIGRATIONS) {
|
|
57
65
|
if (appliedIds.has(migration.id)) continue;
|
|
66
|
+
|
|
58
67
|
_db.exec("BEGIN");
|
|
59
68
|
try {
|
|
60
69
|
_db.exec(migration.sql);
|
|
@@ -2,53 +2,52 @@
|
|
|
2
2
|
* Database connection for microservice-travel
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
return join(
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-travel", "data.db");
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
// Check for .microservices in current or parent directories
|
|
19
19
|
let dir = resolve(process.cwd());
|
|
20
20
|
while (true) {
|
|
21
|
-
const candidate = join(dir, ".microservices", "microservice-travel", "data.db");
|
|
22
21
|
const msDir = join(dir, ".microservices");
|
|
23
|
-
if (existsSync(msDir)) return
|
|
22
|
+
if (existsSync(msDir)) return join(msDir, "microservice-travel", "data.db");
|
|
24
23
|
const parent = dirname(dir);
|
|
25
24
|
if (parent === dir) break;
|
|
26
25
|
dir = parent;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
// Global fallback
|
|
30
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true });
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
38
34
|
}
|
|
35
|
+
return join(newDir, "microservice-travel", "data.db");
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
export function getDatabase(): Database {
|
|
42
39
|
if (_db) return _db;
|
|
43
40
|
|
|
44
41
|
const dbPath = getDbPath();
|
|
45
|
-
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
_db
|
|
49
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
50
50
|
|
|
51
|
-
// Create migrations table
|
|
52
51
|
_db.exec(`
|
|
53
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
54
53
|
id INTEGER PRIMARY KEY,
|
|
@@ -57,7 +56,6 @@ export function getDatabase(): Database {
|
|
|
57
56
|
)
|
|
58
57
|
`);
|
|
59
58
|
|
|
60
|
-
// Apply pending migrations
|
|
61
59
|
const applied = _db
|
|
62
60
|
.query("SELECT id FROM _migrations ORDER BY id")
|
|
63
61
|
.all() as { id: number }[];
|
|
@@ -2,53 +2,52 @@
|
|
|
2
2
|
* Database connection for microservice-wiki
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SqliteAdapter } from "@hasna/cloud";
|
|
6
|
+
import type { Database } from "bun:sqlite";
|
|
7
|
+
import { existsSync, mkdirSync, cpSync } from "node:fs";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { MIGRATIONS } from "./migrations.js";
|
|
9
10
|
|
|
10
11
|
let _db: Database | null = null;
|
|
11
12
|
|
|
12
13
|
function getDbPath(): string {
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
return join(
|
|
14
|
+
const explicit = process.env["HASNA_MICROSERVICES_DIR"] ?? process.env["MICROSERVICES_DIR"];
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return join(explicit, "microservice-wiki", "data.db");
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
// Check for .microservices in current or parent directories
|
|
19
19
|
let dir = resolve(process.cwd());
|
|
20
20
|
while (true) {
|
|
21
|
-
const candidate = join(dir, ".microservices", "microservice-wiki", "data.db");
|
|
22
21
|
const msDir = join(dir, ".microservices");
|
|
23
|
-
if (existsSync(msDir)) return
|
|
22
|
+
if (existsSync(msDir)) return join(msDir, "microservice-wiki", "data.db");
|
|
24
23
|
const parent = dirname(dir);
|
|
25
24
|
if (parent === dir) break;
|
|
26
25
|
dir = parent;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
// Global fallback
|
|
30
28
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true });
|
|
29
|
+
const newDir = join(home, ".hasna", "microservices");
|
|
30
|
+
const oldDir = join(home, ".microservices");
|
|
31
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
32
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
33
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
38
34
|
}
|
|
35
|
+
return join(newDir, "microservice-wiki", "data.db");
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
export function getDatabase(): Database {
|
|
42
39
|
if (_db) return _db;
|
|
43
40
|
|
|
44
41
|
const dbPath = getDbPath();
|
|
45
|
-
|
|
42
|
+
const dir = dirname(resolve(dbPath));
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
_db
|
|
49
|
-
|
|
47
|
+
const adapter = new SqliteAdapter(dbPath);
|
|
48
|
+
_db = adapter.raw;
|
|
49
|
+
// SqliteAdapter already sets WAL and foreign_keys
|
|
50
50
|
|
|
51
|
-
// Create migrations table
|
|
52
51
|
_db.exec(`
|
|
53
52
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
54
53
|
id INTEGER PRIMARY KEY,
|
|
@@ -57,7 +56,6 @@ export function getDatabase(): Database {
|
|
|
57
56
|
)
|
|
58
57
|
`);
|
|
59
58
|
|
|
60
|
-
// Apply pending migrations
|
|
61
59
|
const applied = _db
|
|
62
60
|
.query("SELECT id FROM _migrations ORDER BY id")
|
|
63
61
|
.all() as { id: number }[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/microservices",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Mini business apps for AI agents - invoices, contacts, bookkeeping and more, each with its own SQLite database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"typescript": "^5"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@hasna/cloud": "^0.1.
|
|
58
|
+
"@hasna/cloud": "^0.1.24",
|
|
59
59
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
60
60
|
"chalk": "^5.3.0",
|
|
61
61
|
"commander": "^12.1.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-black:#000;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-background:oklch(100% 0 0);--color-foreground:oklch(14.5% 0 0);--color-card:oklch(100% 0 0);--color-primary:oklch(20.5% 0 0);--color-primary-foreground:oklch(98.5% 0 0);--color-muted:oklch(96.5% 0 0);--color-muted-foreground:oklch(55.6% 0 0);--color-accent:oklch(96.5% 0 0);--color-destructive:oklch(57.7% .245 27.325);--color-border:oklch(92.2% 0 0);--color-success:oklch(59.6% .145 163.225);--color-warning:oklch(68.1% .162 75.834);--color-info:oklch(62.3% .214 259.815)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.fixed{position:fixed}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.right-0{right:calc(var(--spacing) * 0)}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-1{margin-left:calc(var(--spacing) * 1)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.min-h-screen{min-height:100vh}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-full{width:100%}.w-px{width:1px}.max-w-7xl{max-width:var(--container-7xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-primary\/30{border-color:#1717174d}@supports (color:color-mix(in lab,red,red)){.border-primary\/30{border-color:color-mix(in oklab,var(--color-primary) 30%,transparent)}}.bg-accent{background-color:var(--color-accent)}.bg-background{background-color:var(--color-background)}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab,red,red)){.bg-black\/20{background-color:color-mix(in oklab,var(--color-black) 20%,transparent)}}.bg-black\/30{background-color:#0000004d}@supports (color:color-mix(in lab,red,red)){.bg-black\/30{background-color:color-mix(in oklab,var(--color-black) 30%,transparent)}}.bg-border{background-color:var(--color-border)}.bg-card{background-color:var(--color-card)}.bg-destructive\/10{background-color:#e400141a}@supports (color:color-mix(in lab,red,red)){.bg-destructive\/10{background-color:color-mix(in oklab,var(--color-destructive) 10%,transparent)}}.bg-info\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-info\/10{background-color:color-mix(in oklab,var(--color-info) 10%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted\/30{background-color:#f3f3f34d}@supports (color:color-mix(in lab,red,red)){.bg-muted\/30{background-color:color-mix(in oklab,var(--color-muted) 30%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-primary\/5{background-color:#1717170d}@supports (color:color-mix(in lab,red,red)){.bg-primary\/5{background-color:color-mix(in oklab,var(--color-primary) 5%,transparent)}}.bg-success\/10{background-color:#0097671a}@supports (color:color-mix(in lab,red,red)){.bg-success\/10{background-color:color-mix(in oklab,var(--color-success) 10%,transparent)}}.bg-warning\/10{background-color:#cd89001a}@supports (color:color-mix(in lab,red,red)){.bg-warning\/10{background-color:color-mix(in oklab,var(--color-warning) 10%,transparent)}}.p-1{padding:calc(var(--spacing) * 1)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-20{padding-block:calc(var(--spacing) * 20)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.text-left{text-align:left}.text-right{text-align:right}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-destructive{color:var(--color-destructive)}.text-foreground{color:var(--color-foreground)}.text-info{color:var(--color-info)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-success{color:var(--color-success)}.text-warning{color:var(--color-warning)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-primary\/20{--tw-ring-color:#17171733}@supports (color:color-mix(in lab,red,red)){.ring-primary\/20{--tw-ring-color:color-mix(in oklab, var(--color-primary) 20%, transparent)}}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-accent\/50:hover{background-color:#f3f3f380}@supports (color:color-mix(in lab,red,red)){.hover\:bg-accent\/50:hover{background-color:color-mix(in oklab,var(--color-accent) 50%,transparent)}}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:shadow-sm:hover{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:table-cell{display:table-cell}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:48rem){.md\:table-cell{display:table-cell}}@media(min-width:64rem){.lg\:col-span-5{grid-column:span 5/span 5}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}}*{border-color:var(--color-border)}body{background-color:var(--color-background);color:var(--color-foreground);font-family:Inter,system-ui,-apple-system,sans-serif}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
|