baasix 0.1.0

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.
@@ -0,0 +1,121 @@
1
+ import axios, { AxiosInstance } from "axios";
2
+ import { BaasixConfig } from "./get-config.js";
3
+
4
+ let client: AxiosInstance | null = null;
5
+ let authToken: string | null = null;
6
+
7
+ export async function createApiClient(config: BaasixConfig): Promise<AxiosInstance> {
8
+ if (client) {
9
+ return client;
10
+ }
11
+
12
+ client = axios.create({
13
+ baseURL: config.url,
14
+ timeout: 30000,
15
+ headers: {
16
+ "Content-Type": "application/json",
17
+ },
18
+ });
19
+
20
+ // Authenticate if credentials provided
21
+ if (config.token) {
22
+ authToken = config.token;
23
+ client.defaults.headers.common["Authorization"] = `Bearer ${authToken}`;
24
+ } else if (config.email && config.password) {
25
+ try {
26
+ const response = await client.post("/auth/login", {
27
+ email: config.email,
28
+ password: config.password,
29
+ });
30
+ authToken = response.data.token;
31
+ client.defaults.headers.common["Authorization"] = `Bearer ${authToken}`;
32
+ } catch (error) {
33
+ throw new Error(`Failed to authenticate: ${error instanceof Error ? error.message : "Unknown error"}`);
34
+ }
35
+ }
36
+
37
+ return client;
38
+ }
39
+
40
+ export function getAuthToken(): string | null {
41
+ return authToken;
42
+ }
43
+
44
+ export interface SchemaInfo {
45
+ collectionName: string;
46
+ schema: {
47
+ name: string;
48
+ timestamps?: boolean;
49
+ paranoid?: boolean;
50
+ fields: Record<string, FieldDefinition>;
51
+ };
52
+ }
53
+
54
+ export interface FieldDefinition {
55
+ type?: string;
56
+ primaryKey?: boolean;
57
+ allowNull?: boolean;
58
+ unique?: boolean;
59
+ defaultValue?: unknown;
60
+ values?: Record<string, unknown> | string[]; // Can be object with config or array for enums
61
+ validate?: {
62
+ min?: number;
63
+ max?: number;
64
+ len?: [number, number];
65
+ isEmail?: boolean;
66
+ isUrl?: boolean;
67
+ isIP?: boolean;
68
+ isUUID?: number;
69
+ regex?: string;
70
+ [key: string]: unknown;
71
+ };
72
+ // Relation fields
73
+ relType?: "BelongsTo" | "HasOne" | "HasMany" | "BelongsToMany";
74
+ target?: string;
75
+ foreignKey?: string;
76
+ as?: string;
77
+ description?: string;
78
+ SystemGenerated?: boolean | string;
79
+ }
80
+
81
+ export async function fetchSchemas(config: BaasixConfig): Promise<SchemaInfo[]> {
82
+ const client = await createApiClient(config);
83
+ const response = await client.get("/schemas", {
84
+ params: { limit: -1 },
85
+ });
86
+ return response.data.data || [];
87
+ }
88
+
89
+ export interface MigrationInfo {
90
+ id: string;
91
+ version: string;
92
+ name: string;
93
+ status: string;
94
+ type: string;
95
+ executedAt?: string;
96
+ batch?: number;
97
+ }
98
+
99
+ export async function fetchMigrations(config: BaasixConfig): Promise<MigrationInfo[]> {
100
+ const client = await createApiClient(config);
101
+ const response = await client.get("/migrations");
102
+ return response.data.data || [];
103
+ }
104
+
105
+ export async function runMigrations(config: BaasixConfig, options?: {
106
+ dryRun?: boolean;
107
+ step?: number;
108
+ }): Promise<{ success: boolean; message: string; migrations?: MigrationInfo[] }> {
109
+ const client = await createApiClient(config);
110
+ const response = await client.post("/migrations/run", options || {});
111
+ return response.data;
112
+ }
113
+
114
+ export async function rollbackMigrations(config: BaasixConfig, options?: {
115
+ step?: number;
116
+ batch?: number;
117
+ }): Promise<{ success: boolean; message: string }> {
118
+ const client = await createApiClient(config);
119
+ const response = await client.post("/migrations/rollback", options || {});
120
+ return response.data;
121
+ }
@@ -0,0 +1,69 @@
1
+ import { existsSync } from "node:fs";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { parse } from "dotenv";
5
+
6
+ export interface BaasixConfig {
7
+ url: string;
8
+ email?: string;
9
+ password?: string;
10
+ token?: string;
11
+ }
12
+
13
+ /**
14
+ * Load Baasix configuration from .env file or environment variables
15
+ */
16
+ export async function getConfig(cwd: string): Promise<BaasixConfig | null> {
17
+ // Check for .env file
18
+ const envPath = path.join(cwd, ".env");
19
+ let envVars: Record<string, string> = {};
20
+
21
+ if (existsSync(envPath)) {
22
+ const envContent = await fs.readFile(envPath, "utf-8");
23
+ envVars = parse(envContent);
24
+ }
25
+
26
+ // Merge with process.env (process.env takes precedence)
27
+ const mergedEnv = { ...envVars, ...process.env };
28
+
29
+ const url = mergedEnv.BAASIX_URL || mergedEnv.API_URL || "http://localhost:8056";
30
+ const email = mergedEnv.BAASIX_EMAIL || mergedEnv.ADMIN_EMAIL;
31
+ const password = mergedEnv.BAASIX_PASSWORD || mergedEnv.ADMIN_PASSWORD;
32
+ const token = mergedEnv.BAASIX_TOKEN || mergedEnv.BAASIX_AUTH_TOKEN;
33
+
34
+ if (!url) {
35
+ return null;
36
+ }
37
+
38
+ return {
39
+ url,
40
+ email,
41
+ password,
42
+ token,
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Load configuration from baasix.config.js or baasix.config.ts if exists
48
+ */
49
+ export async function loadConfigFile(cwd: string): Promise<Record<string, unknown> | null> {
50
+ const possiblePaths = [
51
+ "baasix.config.js",
52
+ "baasix.config.mjs",
53
+ "baasix.config.ts",
54
+ ];
55
+
56
+ for (const configPath of possiblePaths) {
57
+ const fullPath = path.join(cwd, configPath);
58
+ if (existsSync(fullPath)) {
59
+ try {
60
+ const config = await import(fullPath);
61
+ return config.default || config;
62
+ } catch {
63
+ // Ignore import errors
64
+ }
65
+ }
66
+ }
67
+
68
+ return null;
69
+ }
@@ -0,0 +1,12 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ export async function getPackageInfo(): Promise<Record<string, unknown>> {
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const packageJsonPath = path.resolve(__dirname, "../../package.json");
10
+ const content = await fs.readFile(packageJsonPath, "utf-8");
11
+ return JSON.parse(content);
12
+ }
@@ -0,0 +1,62 @@
1
+ import { exec } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+
5
+ export type PackageManager = "npm" | "pnpm" | "bun" | "yarn";
6
+
7
+ export function detectPackageManager(cwd: string): PackageManager {
8
+ if (existsSync(path.join(cwd, "bun.lockb"))) {
9
+ return "bun";
10
+ }
11
+ if (existsSync(path.join(cwd, "pnpm-lock.yaml"))) {
12
+ return "pnpm";
13
+ }
14
+ if (existsSync(path.join(cwd, "yarn.lock"))) {
15
+ return "yarn";
16
+ }
17
+ return "npm";
18
+ }
19
+
20
+ export function installDependencies({
21
+ dependencies,
22
+ packageManager,
23
+ cwd,
24
+ dev = false,
25
+ }: {
26
+ dependencies: string[];
27
+ packageManager: PackageManager;
28
+ cwd: string;
29
+ dev?: boolean;
30
+ }): Promise<boolean> {
31
+ let installCommand: string;
32
+ const devFlag = dev ? (packageManager === "npm" ? " --save-dev" : " -D") : "";
33
+
34
+ switch (packageManager) {
35
+ case "npm":
36
+ installCommand = `npm install${devFlag}`;
37
+ break;
38
+ case "pnpm":
39
+ installCommand = `pnpm add${devFlag}`;
40
+ break;
41
+ case "bun":
42
+ installCommand = `bun add${devFlag}`;
43
+ break;
44
+ case "yarn":
45
+ installCommand = `yarn add${devFlag}`;
46
+ break;
47
+ default:
48
+ throw new Error("Invalid package manager");
49
+ }
50
+
51
+ const command = `${installCommand} ${dependencies.join(" ")}`;
52
+
53
+ return new Promise((resolve, reject) => {
54
+ exec(command, { cwd }, (error, stdout, stderr) => {
55
+ if (error) {
56
+ reject(new Error(stderr || error.message));
57
+ return;
58
+ }
59
+ resolve(true);
60
+ });
61
+ });
62
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "resolveJsonModule": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: ["esm"],
6
+ outExtension() {
7
+ return {
8
+ js: ".mjs",
9
+ };
10
+ },
11
+ dts: true,
12
+ clean: true,
13
+ banner: {
14
+ js: "#!/usr/bin/env node",
15
+ },
16
+ });