supa-forge 0.1.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.
Files changed (40) hide show
  1. package/README.md +65 -0
  2. package/bin/cli.js +116 -0
  3. package/dist/index.d.ts +210 -0
  4. package/dist/index.js +79 -0
  5. package/dist/index.mjs +1364 -0
  6. package/dist/typeorm.d.ts +26 -0
  7. package/dist/typeorm.js +1 -0
  8. package/dist/typeorm.mjs +15 -0
  9. package/examples/Only CLS/package-lock.json +3140 -0
  10. package/examples/Only CLS/package.json +25 -0
  11. package/examples/Only CLS/src/employee.test.ts +109 -0
  12. package/examples/Only CLS/src/entities/Employee.entity.ts +27 -0
  13. package/examples/Only CLS/src/index.ts +45 -0
  14. package/examples/Only CLS/tsconfig.json +17 -0
  15. package/examples/Only CLS/vite.config.ts +8 -0
  16. package/examples/Only RLS/package-lock.json +3140 -0
  17. package/examples/Only RLS/package.json +25 -0
  18. package/examples/Only RLS/src/entities/Note.entity.ts +40 -0
  19. package/examples/Only RLS/src/entities/User.entity.ts +29 -0
  20. package/examples/Only RLS/src/index.ts +51 -0
  21. package/examples/Only RLS/src/notes.test.ts +123 -0
  22. package/examples/Only RLS/tsconfig.json +17 -0
  23. package/examples/Only RLS/vite.config.ts +8 -0
  24. package/examples/RBAC + CLS + RLS/package-lock.json +3140 -0
  25. package/examples/RBAC + CLS + RLS/package.json +21 -0
  26. package/examples/RBAC + CLS + RLS/src/entities/Project.entity.ts +47 -0
  27. package/examples/RBAC + CLS + RLS/src/entities/User.entity.ts +31 -0
  28. package/examples/RBAC + CLS + RLS/src/entities/UserRole.entity.ts +110 -0
  29. package/examples/RBAC + CLS + RLS/src/index.ts +42 -0
  30. package/examples/RBAC + CLS + RLS/src/project.test.ts +117 -0
  31. package/examples/RBAC + CLS + RLS/tsconfig.json +17 -0
  32. package/examples/RBAC + CLS + RLS/vite.config.ts +8 -0
  33. package/examples/Without Security/package-lock.json +3940 -0
  34. package/examples/Without Security/package.json +25 -0
  35. package/examples/Without Security/src/entities/Pharmacy.entity.ts +20 -0
  36. package/examples/Without Security/src/index.ts +52 -0
  37. package/examples/Without Security/src/pharmacy.test.ts +104 -0
  38. package/examples/Without Security/tsconfig.json +17 -0
  39. package/examples/Without Security/vite.config.ts +8 -0
  40. package/package.json +72 -0
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "example-without-security",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "generate": "vite-node src/index.ts --generate",
7
+ "apply": "vite-node src/index.ts --apply",
8
+ "temp:generate": "vite-node src/index.ts --temp --generate",
9
+ "temp:apply": "vite-node src/index.ts --temp --apply",
10
+ "migration:create": "vite-node src/index.ts migration:create",
11
+ "docgen": "vite-node src/index.ts --docgen",
12
+ "test": "vitest run"
13
+ },
14
+ "dependencies": {
15
+ "supaforge": "file:../.."
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^20.0.0",
19
+ "typeorm": "^0.3.17",
20
+ "typescript": "^5.0.0",
21
+ "vite": "^8.0.1",
22
+ "vite-node": "^6.0.0",
23
+ "vitest": "^0.34.0"
24
+ }
25
+ }
@@ -0,0 +1,20 @@
1
+ import 'reflect-metadata';
2
+ import { Entity, PrimaryGeneratedColumn, Column } from 'supaforge/typeorm';
3
+
4
+ @Entity('pharmacies')
5
+ export class Pharmacy {
6
+ @PrimaryGeneratedColumn('uuid')
7
+ id!: string;
8
+
9
+ @Column({ type: 'text' })
10
+ name!: string;
11
+
12
+ @Column({ type: 'text' })
13
+ address!: string;
14
+
15
+ @Column({ type: 'text', nullable: true })
16
+ phone!: string;
17
+
18
+ @Column({ type: 'boolean', default: true })
19
+ isOpen!: boolean;
20
+ }
@@ -0,0 +1,52 @@
1
+ import 'reflect-metadata';
2
+ import * as path from 'path';
3
+ import 'dotenv/config';
4
+ import { runSupaforge, createMigrationTemplate, applyGeneratedMigrations, generateDocumentation, extractCliOptions, RunnerOptions } from 'supaforge';
5
+
6
+ async function main() {
7
+ const flags = process.argv;
8
+ const cliOptions = extractCliOptions(flags);
9
+
10
+ const options: RunnerOptions = {
11
+ ...cliOptions,
12
+ dbConfig: {
13
+ host: process.env.DB_HOST || 'localhost',
14
+ port: Number(process.env.DB_PORT) || 5432,
15
+ user: process.env.DB_USER || 'postgres',
16
+ password: process.env.DB_PASSWORD || 'postgres',
17
+ database: flags.includes('--temp') ? 'temp_pharmacy' : (process.env.DB_NAME || 'postgres'),
18
+ },
19
+ entityPath: path.join(__dirname, 'entities'),
20
+ outputDir: path.join(process.cwd(), 'migrations'),
21
+ syncSchema: cliOptions.syncSchema || flags.includes('--temp'),
22
+ cls: false,
23
+ rls: false,
24
+ };
25
+
26
+ try {
27
+ if (flags.includes('migration:create')) {
28
+ return await createMigrationTemplate(options);
29
+ }
30
+
31
+ if (flags.includes('--apply')) {
32
+ return await applyGeneratedMigrations(options);
33
+ }
34
+
35
+ if (flags.includes('--generate')) {
36
+ const sql = await runSupaforge(options);
37
+ console.log('Migration Sql Snippet:\n' + sql.split('\n').slice(0, 10).join('\n') + '...');
38
+ console.log('\nUse --apply to push to DB.');
39
+ return;
40
+ }
41
+
42
+ if (flags.includes('--docgen')) {
43
+ return await generateDocumentation(options);
44
+ }
45
+
46
+ } catch (error) {
47
+ console.error('\nError:', error);
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ main();
@@ -0,0 +1,104 @@
1
+ import 'reflect-metadata';
2
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
3
+ import 'dotenv/config';
4
+ import { DataSource, QueryRunner } from 'supaforge/typeorm';
5
+ import { runSupaforge, applyGeneratedMigrations } from 'supaforge';
6
+ import { Pharmacy } from './entities/Pharmacy.entity';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs';
9
+ import { fileURLToPath } from 'url';
10
+ import process from 'process';
11
+
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ describe('Pharmacy CRUD Tests (Without Security)', () => {
17
+ let dataSource: DataSource;
18
+ let queryRunner: QueryRunner;
19
+
20
+ const DB_CONFIG = {
21
+ host: process.env.DB_HOST || 'localhost',
22
+ port: Number(process.env.DB_PORT) || 5432,
23
+ user: process.env.DB_USER || 'postgres',
24
+ password: process.env.DB_PASSWORD || 'postgres',
25
+ database: process.env.DB_NAME || 'postgres',
26
+ };
27
+
28
+ beforeAll(async () => {
29
+ const migrationDir = path.join(process.cwd(), 'migrations');
30
+ if (fs.existsSync(migrationDir)) {
31
+ fs.rmSync(migrationDir, { recursive: true, force: true });
32
+ }
33
+
34
+ const options = {
35
+ dbConfig: DB_CONFIG,
36
+ entityPath: path.join(__dirname, 'entities'),
37
+ outputDir: migrationDir,
38
+ syncSchema: true,
39
+ migrationName: 'PharmacyInit',
40
+ rls: false,
41
+ cls: false
42
+ };
43
+
44
+ await runSupaforge(options);
45
+ await applyGeneratedMigrations(options);
46
+
47
+ dataSource = new DataSource({
48
+ type: 'postgres',
49
+ ...DB_CONFIG,
50
+ username: DB_CONFIG.user,
51
+ entities: [Pharmacy],
52
+ });
53
+
54
+ await dataSource.initialize();
55
+ queryRunner = dataSource.createQueryRunner();
56
+ await queryRunner.connect();
57
+
58
+ await queryRunner.query('DELETE FROM pharmacies');
59
+ }, 45000);
60
+
61
+ afterAll(async () => {
62
+ if (queryRunner) await queryRunner.release();
63
+ if (dataSource) await dataSource.destroy();
64
+ });
65
+
66
+ it('should Create a new pharmacy', async () => {
67
+ const pharmacy = new Pharmacy();
68
+ pharmacy.name = 'Central Pharmacy';
69
+ pharmacy.address = '123 Health St';
70
+ pharmacy.phone = '555-0101';
71
+ pharmacy.isOpen = true;
72
+
73
+ const saved = await dataSource.getRepository(Pharmacy).save(pharmacy);
74
+ expect(saved.id).toBeDefined();
75
+ expect(saved.name).toBe('Central Pharmacy');
76
+ });
77
+
78
+ it('should Read a pharmacy', async () => {
79
+ const pharmacies = await dataSource.getRepository(Pharmacy).find();
80
+ expect(pharmacies.length).toBeGreaterThan(0);
81
+ expect(pharmacies[0].name).toBe('Central Pharmacy');
82
+ });
83
+
84
+ it('should Update a pharmacy', async () => {
85
+ const pharmacies = await dataSource.getRepository(Pharmacy).find();
86
+ const pharmacy = pharmacies.find(p => p.name === 'Central Pharmacy');
87
+ expect(pharmacy).toBeDefined();
88
+ pharmacy!.name = 'Updated City Pharmacy';
89
+ await dataSource.getRepository(Pharmacy).save(pharmacy!);
90
+
91
+ const updated = await dataSource.getRepository(Pharmacy).findOneBy({ id: pharmacy!.id });
92
+ expect(updated?.name).toBe('Updated City Pharmacy');
93
+ });
94
+
95
+ it('should Delete a pharmacy', async () => {
96
+ const pharmacy = await dataSource.getRepository(Pharmacy).findOneBy({ name: 'Updated City Pharmacy' });
97
+ expect(pharmacy).toBeDefined();
98
+
99
+ await dataSource.getRepository(Pharmacy).remove(pharmacy!);
100
+
101
+ const deleted = await dataSource.getRepository(Pharmacy).findOneBy({ id: pharmacy!.id });
102
+ expect(deleted).toBeNull();
103
+ });
104
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "experimentalDecorators": true,
9
+ "emitDecoratorMetadata": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "noImplicitAny": true,
13
+ "outDir": "./dist",
14
+ "types": ["node"]
15
+ },
16
+ "include": ["src/**/*"]
17
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ },
8
+ });
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "supa-forge",
3
+ "version": "0.1.1",
4
+ "description": "Supabase Forge - Scaffolding and Core Logic",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "supaforge": "./bin/cli.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "bin",
14
+ "examples",
15
+ "!**/node_modules/**",
16
+ "!**/.env",
17
+ "!**/*.log",
18
+ "!**/.DS_Store",
19
+ "!**/migrations/**",
20
+ "README.md"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "require": "./dist/index.cjs",
25
+ "import": "./dist/index.js",
26
+ "types": "./dist/index.d.ts"
27
+ },
28
+ "./typeorm": {
29
+ "require": "./dist/typeorm.cjs",
30
+ "import": "./dist/typeorm.js",
31
+ "types": "./dist/typeorm.d.ts"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "build": "vite build",
36
+ "test": "npm run build && for d in tests/*; do (cd \"$d\" && npm install && npm test || exit 1); done",
37
+ "cli": "node bin/cli.js",
38
+ "lint": "eslint .",
39
+ "lint:fix": "eslint . --fix"
40
+ },
41
+ "dependencies": {
42
+ "chalk": "^4.1.2",
43
+ "dotenv": "^16.4.5",
44
+ "fs-extra": "^11.2.0",
45
+ "inquirer": "^8.2.5",
46
+ "js-yaml": "^4.1.1",
47
+ "pg": "^8.11.3",
48
+ "reflect-metadata": "^0.1.13",
49
+ "zod": "^3.23.8"
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^10.0.1",
53
+ "@stylistic/eslint-plugin": "^5.10.0",
54
+ "@types/fs-extra": "^11.0.4",
55
+ "@types/inquirer": "^8.2.6",
56
+ "@types/js-yaml": "^4.0.9",
57
+ "@types/node": "^20.0.0",
58
+ "@types/pg": "^8.20.0",
59
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
60
+ "@typescript-eslint/parser": "^8.57.1",
61
+ "eslint": "^10.1.0",
62
+ "typeorm": "^0.3.17",
63
+ "typescript": "^5.0.0",
64
+ "typescript-eslint": "^8.57.1",
65
+ "vite": "^5.0.0",
66
+ "vite-node": "^1.0.0",
67
+ "vite-plugin-dts": "^3.7.0"
68
+ },
69
+ "peerDependencies": {
70
+ "typeorm": "^0.3.17"
71
+ }
72
+ }