bunsane 0.1.0 → 0.1.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.
Files changed (82) hide show
  1. package/.github/workflows/deploy-docs.yml +57 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +2 -28
  4. package/TODO.md +8 -1
  5. package/bun.lock +3 -0
  6. package/config/upload.config.ts +135 -0
  7. package/core/App.ts +168 -4
  8. package/core/ArcheType.ts +122 -0
  9. package/core/BatchLoader.ts +100 -0
  10. package/core/ComponentRegistry.ts +4 -3
  11. package/core/Components.ts +2 -2
  12. package/core/Decorators.ts +15 -8
  13. package/core/Entity.ts +193 -14
  14. package/core/EntityCache.ts +15 -0
  15. package/core/EntityHookManager.ts +855 -0
  16. package/core/EntityManager.ts +12 -2
  17. package/core/ErrorHandler.ts +64 -7
  18. package/core/FileValidator.ts +284 -0
  19. package/core/Query.ts +503 -85
  20. package/core/RequestContext.ts +24 -0
  21. package/core/RequestLoaders.ts +89 -0
  22. package/core/SchedulerManager.ts +710 -0
  23. package/core/UploadManager.ts +261 -0
  24. package/core/components/UploadComponent.ts +206 -0
  25. package/core/decorators/EntityHooks.ts +190 -0
  26. package/core/decorators/ScheduledTask.ts +83 -0
  27. package/core/events/EntityLifecycleEvents.ts +177 -0
  28. package/core/processors/ImageProcessor.ts +423 -0
  29. package/core/storage/LocalStorageProvider.ts +290 -0
  30. package/core/storage/StorageProvider.ts +112 -0
  31. package/database/DatabaseHelper.ts +183 -58
  32. package/database/index.ts +5 -5
  33. package/database/sqlHelpers.ts +7 -0
  34. package/docs/README.md +149 -0
  35. package/docs/_coverpage.md +36 -0
  36. package/docs/_sidebar.md +23 -0
  37. package/docs/api/core.md +568 -0
  38. package/docs/api/hooks.md +554 -0
  39. package/docs/api/index.md +222 -0
  40. package/docs/api/query.md +678 -0
  41. package/docs/api/service.md +744 -0
  42. package/docs/core-concepts/archetypes.md +512 -0
  43. package/docs/core-concepts/components.md +498 -0
  44. package/docs/core-concepts/entity.md +314 -0
  45. package/docs/core-concepts/hooks.md +683 -0
  46. package/docs/core-concepts/query.md +588 -0
  47. package/docs/core-concepts/services.md +647 -0
  48. package/docs/examples/code-examples.md +425 -0
  49. package/docs/getting-started.md +337 -0
  50. package/docs/index.html +97 -0
  51. package/gql/Generator.ts +58 -35
  52. package/gql/decorators/Upload.ts +176 -0
  53. package/gql/helpers.ts +67 -0
  54. package/gql/index.ts +65 -31
  55. package/gql/types.ts +1 -1
  56. package/index.ts +79 -11
  57. package/package.json +19 -10
  58. package/rest/Generator.ts +3 -0
  59. package/rest/index.ts +22 -0
  60. package/service/Service.ts +1 -1
  61. package/service/ServiceRegistry.ts +10 -6
  62. package/service/index.ts +12 -1
  63. package/tests/bench/insert.bench.ts +59 -0
  64. package/tests/bench/relations.bench.ts +269 -0
  65. package/tests/bench/sorting.bench.ts +415 -0
  66. package/tests/component-hooks.test.ts +1409 -0
  67. package/tests/component.test.ts +338 -0
  68. package/tests/errorHandling.test.ts +155 -0
  69. package/tests/hooks.test.ts +666 -0
  70. package/tests/query-sorting.test.ts +101 -0
  71. package/tests/relations.test.ts +169 -0
  72. package/tests/scheduler.test.ts +724 -0
  73. package/tsconfig.json +35 -34
  74. package/types/graphql.types.ts +87 -0
  75. package/types/hooks.types.ts +141 -0
  76. package/types/scheduler.types.ts +165 -0
  77. package/types/upload.types.ts +184 -0
  78. package/upload/index.ts +140 -0
  79. package/utils/UploadHelper.ts +305 -0
  80. package/utils/cronParser.ts +366 -0
  81. package/utils/errorMessages.ts +151 -0
  82. package/core/Events.ts +0 -0
@@ -2,6 +2,34 @@ import db from "database";
2
2
  import { logger as MainLogger } from "core/Logger";
3
3
  const logger = MainLogger.child({ scope: "DatabaseHelper" });
4
4
 
5
+ const BUNSANE_RELATION_TYPED_COLUMN = process.env.BUNSANE_RELATION_TYPED_COLUMN === 'true' || false;
6
+
7
+ const validateIdentifier = (str: string, maxLength: number = 64): string => {
8
+ if (!str || typeof str !== 'string' || str.length === 0 || str.length > maxLength) {
9
+ throw new Error(`Invalid identifier: ${str}`);
10
+ }
11
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(str)) {
12
+ throw new Error(`Invalid identifier format: ${str}`);
13
+ }
14
+ return str;
15
+ };
16
+
17
+ const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
18
+
19
+ const retryWithBackoff = async (fn: () => Promise<void>, maxRetries: number = 3, baseDelay: number = 1000) => {
20
+ for (let i = 0; i < maxRetries; i++) {
21
+ try {
22
+ await fn();
23
+ return;
24
+ } catch (error) {
25
+ if (i === maxRetries - 1) throw error;
26
+ const delay = baseDelay * Math.pow(2, i);
27
+ logger.warn(`Operation failed, retrying in ${delay}ms: ${error}`);
28
+ await sleep(delay);
29
+ }
30
+ }
31
+ };
32
+
5
33
  export const GetSchema = async () => {
6
34
  const dbSchema = await db`SELECT table_name
7
35
  FROM information_schema.tables
@@ -20,60 +48,145 @@ export const HasValidBaseTable = async (): Promise<boolean> => {
20
48
 
21
49
  export const PrepareDatabase = async () => {
22
50
  logger.trace(`Initializing Database.`);
23
- await SetupDatabaseExtensions();
24
- await CreateEntityTable();
25
- await CreateComponentTable();
26
- await CreateEntityComponentTable();
51
+ try {
52
+ await SetupDatabaseExtensions();
53
+ } catch (error) {
54
+ logger.error(`Failed to setup database extensions: ${error}`);
55
+ throw error;
56
+ }
57
+ try {
58
+ await CreateEntityTable();
59
+ } catch (error) {
60
+ logger.error(`Failed to create entity table: ${error}`);
61
+ throw error;
62
+ }
63
+ try {
64
+ await CreateComponentTable();
65
+ } catch (error) {
66
+ logger.error(`Failed to create component table: ${error}`);
67
+ throw error;
68
+ }
69
+ try {
70
+ await CreateEntityComponentTable();
71
+ } catch (error) {
72
+ logger.error(`Failed to create entity component table: ${error}`);
73
+ throw error;
74
+ }
27
75
  }
28
76
 
77
+ export const GetDatabaseDataSize = async () => {
78
+ const result = await db`SELECT
79
+ relname AS table_name,
80
+ pg_size_pretty(pg_total_relation_size(oid)) AS total_size_pretty,
81
+ ROUND(pg_total_relation_size(oid) / (1024.0 * 1024.0), 2) AS total_size_mb
82
+ FROM
83
+ pg_class
84
+ WHERE
85
+ relkind = 'r' -- 'r' for regular table, 'p' for partitioned table
86
+ AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public') -- Or your specific schema
87
+ ORDER BY
88
+ pg_total_relation_size(oid) DESC;`;
89
+ return result;
90
+ }
91
+
92
+
29
93
  export const SetupDatabaseExtensions = async () => {
30
- return new Promise(async resolve => {
31
- // await db`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`;
32
- return resolve(true);
33
- })
94
+ // await db`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`;
34
95
  }
35
96
 
36
97
  export const CreateEntityTable = async () => {
37
- return new Promise(async resolve => {
38
- await db`CREATE TABLE IF NOT EXISTS entities (
39
- id UUID PRIMARY KEY,
40
- created_at TIMESTAMP DEFAULT NOW(),
41
- updated_at TIMESTAMP DEFAULT NOW()
42
- );`;
43
- return resolve(true);
44
- });
98
+ await db`CREATE TABLE IF NOT EXISTS entities (
99
+ id UUID PRIMARY KEY,
100
+ created_at TIMESTAMP DEFAULT NOW(),
101
+ updated_at TIMESTAMP DEFAULT NOW(),
102
+ deleted_at TIMESTAMP
103
+ );`;
45
104
  }
46
105
 
47
- export const CreateComponentTable = () => {
48
- return new Promise(async resolve => {
49
- await db`CREATE TABLE IF NOT EXISTS components (
50
- id UUID,
51
- entity_id UUID REFERENCES entities(id),
52
- type_id varchar(64) NOT NULL,
53
- name varchar(128),
54
- data jsonb,
55
- created_at TIMESTAMP DEFAULT NOW(),
56
- updated_at TIMESTAMP DEFAULT NOW(),
57
- PRIMARY KEY (id, type_id, entity_id)
58
- ) PARTITION BY LIST (type_id);`;
59
- await db`CREATE INDEX IF NOT EXISTS idx_components_entity_id ON components (entity_id);`
60
- await db`CREATE INDEX IF NOT EXISTS idx_components_type_id ON components (type_id);`
61
- await db`CREATE INDEX IF NOT EXISTS idx_components_data_gin ON components USING GIN (data);`
62
- return resolve(true);
63
- });
106
+ export const CreateComponentTable = async () => {
107
+ await db`CREATE TABLE IF NOT EXISTS components (
108
+ id UUID,
109
+ entity_id UUID REFERENCES entities(id),
110
+ type_id varchar(64) NOT NULL,
111
+ name varchar(128),
112
+ data jsonb,
113
+ created_at TIMESTAMP DEFAULT NOW(),
114
+ updated_at TIMESTAMP DEFAULT NOW(),
115
+ deleted_at TIMESTAMP,
116
+ PRIMARY KEY (id, type_id, entity_id)
117
+ ) PARTITION BY LIST (type_id);`;
118
+ await db`CREATE INDEX IF NOT EXISTS idx_components_entity_id ON components (entity_id);`
119
+ await db`CREATE INDEX IF NOT EXISTS idx_components_type_id ON components (type_id);`
120
+ await db`CREATE INDEX IF NOT EXISTS idx_components_data_gin ON components USING GIN (data);`
121
+
122
+ // Phase 2A: Add composite indexes for sorting optimization
123
+ await db`CREATE INDEX IF NOT EXISTS idx_components_entity_type_deleted ON components (entity_id, type_id, deleted_at);`
124
+ await db`CREATE INDEX IF NOT EXISTS idx_components_type_deleted ON components (type_id, deleted_at) WHERE deleted_at IS NULL;`
125
+ await db`CREATE INDEX IF NOT EXISTS idx_components_deleted_entity ON components (deleted_at, entity_id) WHERE deleted_at IS NULL;`
126
+ }
127
+
128
+ export const UpdateComponentIndexes = async (table_name: string, indexedProperties: string[]) => {
129
+ try {
130
+ table_name = validateIdentifier(table_name);
131
+ indexedProperties = indexedProperties.map(prop => validateIdentifier(prop));
132
+ logger.trace(`Updating indexes for component table: ${table_name}`);
133
+ const indexes_list = await db.unsafe(`
134
+ SELECT indexname
135
+ FROM pg_indexes
136
+ WHERE tablename = '${table_name}'
137
+ `);
138
+ const existingIndexes = indexes_list.map((row: any) => row.indexname);
139
+ const addedIndexes = new Set<string>();
140
+
141
+ // Check and create indexes for any new indexed properties
142
+ if (indexedProperties && indexedProperties.length > 0) {
143
+ for (const prop of indexedProperties) {
144
+ const indexName = `idx_${table_name}_${prop}_gin`;
145
+ if (!existingIndexes.includes(indexName)) {
146
+ logger.trace(`Creating missing index ${indexName} for property ${prop}`);
147
+ await retryWithBackoff(async () => {
148
+ await db.unsafe(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${indexName} ON ${table_name} USING GIN ((data->'${prop}'))`);
149
+ });
150
+ addedIndexes.add(indexName);
151
+ } else {
152
+ logger.trace(`Index ${indexName} for property ${prop} already exists`);
153
+ }
154
+ }
155
+ }
156
+
157
+ // Remove indexes for properties that are no longer indexed
158
+ for (const index of existingIndexes) {
159
+ const match = index.match(new RegExp(`^idx_${table_name}_(.*)_gin$`));
160
+ if (match) {
161
+ const prop = match[1];
162
+ if (!indexedProperties.includes(prop) && !addedIndexes.has(index)) {
163
+ await retryWithBackoff(async () => {
164
+ await db.unsafe(`DROP INDEX CONCURRENTLY IF EXISTS ${index}`);
165
+ });
166
+ logger.info(`Dropped obsolete index ${index} for property ${prop}`);
167
+ }
168
+ }
169
+ }
170
+ } catch (error) {
171
+ logger.error(`Failed to update component indexes for ${table_name}: ${error}`);
172
+ throw error;
173
+ }
64
174
  }
65
175
 
66
176
 
67
177
  export const CreateComponentPartitionTable = async (comp_name: string, type_id: string, indexedProperties?: string[]) => {
68
178
  try {
179
+ comp_name = validateIdentifier(comp_name);
180
+ // type_id is a value, not identifier, so no validation
181
+ if (indexedProperties) {
182
+ indexedProperties = indexedProperties.map(prop => validateIdentifier(prop));
183
+ }
69
184
  logger.trace(`Attempt adding partition table for component: ${comp_name}`);
70
185
  const table_name = `components_${comp_name.toLowerCase().replace(/\s+/g, '_')}`;
71
186
  logger.trace(`Checking for existing partition table: ${table_name}`);
72
- const existingPartition = await db`
73
- SELECT 1 FROM information_schema.tables
74
- WHERE table_name = ${table_name}
75
- AND table_schema = 'public'
76
- `;
187
+ const existingPartition = await db.unsafe(`SELECT 1 FROM information_schema.tables
188
+ WHERE table_name = '${table_name}'
189
+ AND table_schema = 'public'`);
77
190
  logger.trace(`Existing partition check result: ${existingPartition.length > 0 ? 'found' : 'not found'}`);
78
191
 
79
192
  if (existingPartition.length > 0) {
@@ -82,47 +195,54 @@ export const CreateComponentPartitionTable = async (comp_name: string, type_id:
82
195
  }
83
196
  logger.trace(`Creating partition table: ${table_name}`);
84
197
 
85
- await db.unsafe(`CREATE TABLE IF NOT EXISTS ${table_name}
198
+ await retryWithBackoff(async () => {
199
+ await db.unsafe(`CREATE TABLE IF NOT EXISTS ${table_name}
86
200
  PARTITION OF components
87
- FOR VALUES IN ('${type_id}');`);
88
-
89
- if (indexedProperties && indexedProperties.length > 0) {
90
- for (const prop of indexedProperties) {
91
- const indexName = `idx_${table_name}_${prop}`;
92
- await db.unsafe(`CREATE INDEX IF NOT EXISTS ${indexName} ON ${table_name} USING GIN ((data->'${prop}'))`);
93
- logger.trace(`Created index ${indexName} for property ${prop}`);
94
- }
95
- }
96
-
201
+ FOR VALUES IN ('${type_id}')`);
202
+ });
97
203
  logger.trace(`Successfully created partition table: ${table_name}`);
204
+
205
+ if (BUNSANE_RELATION_TYPED_COLUMN && indexedProperties?.includes('value')) {
206
+ logger.trace(`Adding typed FK column for ${table_name}`);
207
+ await retryWithBackoff(async () => {
208
+ await db.unsafe(`ALTER TABLE ${table_name} ADD COLUMN IF NOT EXISTS fk_id UUID GENERATED ALWAYS AS ((data->>'value')::UUID) STORED`);
209
+ });
210
+ await retryWithBackoff(async () => {
211
+ await db.unsafe(`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_${table_name}_fk_id ON ${table_name} (fk_id)`);
212
+ });
213
+ logger.trace(`Added fk_id column and index for ${table_name}`);
214
+ }
98
215
 
99
216
  } catch (error) {
100
217
  logger.error(`Failed to create component partition table for ${comp_name}: ${error}`);
101
- throw error;
218
+ // Graceful degradation: log error without crashing
102
219
  }
103
220
  }
104
221
 
105
222
  export const DeleteComponentPartitionTable = async (comp_name: string) => {
106
223
  try {
224
+ comp_name = validateIdentifier(comp_name);
107
225
  const table_name = `components_${comp_name.toLowerCase().replace(/\s+/g, '_')}`;
108
226
 
109
- const existingPartition = await db`
227
+ const existingPartition = await db.unsafe(`
110
228
  SELECT 1 FROM information_schema.tables
111
- WHERE table_name = ${table_name}
229
+ WHERE table_name = '${table_name}'
112
230
  AND table_schema = 'public'
113
- `;
231
+ `);
114
232
 
115
233
  if (existingPartition.length === 0) {
116
234
  logger.info(`Partition table ${table_name} does not exist`);
117
235
  return;
118
236
  }
119
237
 
120
- await db.unsafe(`DROP TABLE IF EXISTS ${table_name}`);
238
+ await retryWithBackoff(async () => {
239
+ await db.unsafe(`DROP TABLE IF EXISTS ${table_name}`);
240
+ });
121
241
  logger.info(`Successfully deleted partition table: ${table_name}`);
122
242
 
123
243
  } catch (error) {
124
244
  logger.error(`Failed to delete component partition table for ${comp_name}: ${error}`);
125
- throw error;
245
+ // Graceful degradation: log error without crashing
126
246
  }
127
247
  }
128
248
 
@@ -130,9 +250,14 @@ export const CreateEntityComponentTable = async () => {
130
250
  await db`CREATE TABLE IF NOT EXISTS entity_components (
131
251
  entity_id UUID REFERENCES entities(id),
132
252
  type_id VARCHAR(64) NOT NULL,
253
+ deleted_at TIMESTAMP,
133
254
  UNIQUE(entity_id, type_id)
134
255
  );`;
135
- await db`CREATE INDEX IF NOT EXISTS idx_entity_components_entity_id ON entity_components (entity_id);`
136
- await db`CREATE INDEX IF NOT EXISTS idx_entity_components_type_id ON entity_components (type_id);`
137
- await db`CREATE INDEX IF NOT EXISTS idx_entity_components_type_entity ON entity_components (type_id, entity_id);`
256
+ await db`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_entity_components_entity_id ON entity_components (entity_id);`
257
+ await db`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_entity_components_type_id ON entity_components (type_id);`
258
+ await db`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_entity_components_type_entity ON entity_components (type_id, entity_id);`
259
+
260
+ // Phase 2A: Add composite indexes for sorting optimization
261
+ await db`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_entity_components_type_entity_deleted ON entity_components (type_id, entity_id, deleted_at);`
262
+ await db`CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_entity_components_deleted_type ON entity_components (deleted_at, type_id) WHERE deleted_at IS NULL;`
138
263
  }
package/database/index.ts CHANGED
@@ -2,11 +2,11 @@ import {SQL} from "bun";
2
2
  import { logger } from "core/Logger";
3
3
 
4
4
  const db = new SQL({
5
- url: `postgres://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASSWORD}@${process.env.POSTGRES_HOST}:5432/${process.env.POSTGRES_DB}`,
6
- // Connection pool settings
7
- max: 10, // Maximum connections in pool
8
- idleTimeout: 0, // Close idle connections after 30s
9
- maxLifetime: 0, // Connection lifetime in seconds (0 = forever)
5
+ url: `postgres://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASSWORD}@${process.env.POSTGRES_HOST}:${process.env.POSTGRES_PORT ?? "5432"}/${process.env.POSTGRES_DB}`,
6
+ // Connection pool settings - FIXED
7
+ max: parseInt(process.env.POSTGRES_MAX_CONNECTIONS ?? '20', 10), // Increased max connections
8
+ idleTimeout: 30000, // Close idle connections after 30s (was 0)
9
+ maxLifetime: 600000, // Connection lifetime 10 minutes (was 0 = forever)
10
10
  connectionTimeout: 30, // Timeout when establishing new connections
11
11
  onclose: (err) => {
12
12
  if (err) {
@@ -0,0 +1,7 @@
1
+ import { sql } from 'bun';
2
+
3
+ export function inList<T>(values: T[], paramIndex: number): { sql: string, params: any[], newParamIndex: number } {
4
+ if (values.length === 0) return { sql: '()', params: [], newParamIndex: paramIndex };
5
+ const placeholders = Array.from({length: values.length}, (_, i) => `$${paramIndex + i}`).join(', ');
6
+ return { sql: `(${placeholders})`, params: values, newParamIndex: paramIndex + values.length };
7
+ }
package/docs/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # BunSane Framework Documentation
2
+
3
+ Welcome to the official documentation for **BunSane** - a batteries-included TypeScript API framework built on the Bun runtime.
4
+
5
+ ## 🎯 What Makes BunSane Special?
6
+
7
+ BunSane revolutionizes API development by combining the power of Entity-Component-System (ECS) architecture with modern TypeScript. Built specifically for Bun's high-performance runtime, it provides a flexible foundation for building scalable applications.
8
+
9
+ ### Key Differentiators
10
+
11
+ - **ECS Architecture**: Flexible data modeling without traditional ORM limitations
12
+ - **Type-Safe Everything**: Full TypeScript integration with compile-time guarantees
13
+ - **Bun-Native Performance**: Optimized for Bun's speed and efficiency
14
+ - **Component-Based Design**: Build complex entities from reusable components
15
+ - **Built-in GraphQL Support**: GraphQL integration with Yoga
16
+
17
+ ## 🚀 Quick Start
18
+
19
+ Get up and running in minutes:
20
+
21
+ ```bash
22
+ # Install BunSane
23
+ bun install bunsane
24
+
25
+ # Create your first entity
26
+ import { Entity, Component, CompData, BaseComponent } from 'bunsane';
27
+
28
+ @Component
29
+ class UserProfile extends BaseComponent {
30
+ @CompData()
31
+ name: string = '';
32
+
33
+ @CompData()
34
+ email: string = '';
35
+ }
36
+
37
+ // Create and save an entity
38
+ const user = Entity.Create();
39
+ user.add(UserProfile, { name: 'John Doe', email: 'john@example.com' });
40
+ await user.save();
41
+ ```
42
+
43
+ ## 📚 Core Architecture
44
+
45
+ BunSane is built around four fundamental concepts:
46
+
47
+ ### 1. **Entities** - Your Data Objects
48
+ Entities are the core data containers in BunSane. Unlike traditional objects, entities are composed of multiple components, allowing for flexible and dynamic data structures.
49
+
50
+ ### 2. **Components** - Data Building Blocks
51
+ Components are pure data structures that define specific aspects of your entities. They're decorated with `@CompData()` and automatically persisted to PostgreSQL.
52
+
53
+ ### 3. **ArcheTypes** - Entity Templates
54
+ ArcheTypes provide reusable templates for creating entities with predefined component sets, reducing code duplication and ensuring consistency.
55
+
56
+ ### 4. **Services** - Business Logic
57
+ Services contain your business logic and can integrate with GraphQL resolvers for API endpoints.
58
+
59
+ ## 🔧 Features
60
+
61
+ - **Lifecycle Hooks**: React to entity creation, updates, and deletion
62
+ - **Query System**: Type-safe querying with filtering
63
+ - **Component Registry**: Automatic component discovery and registration
64
+ - **Entity Caching**: Built-in caching for improved performance
65
+ - **GraphQL Integration**: Basic GraphQL support with Yoga
66
+ - **File Upload Support**: Basic file upload handling
67
+ - **Background Tasks**: Simple scheduled task support
68
+ - **Request Context**: Context management for requests
69
+
70
+ ## 📖 Documentation Sections
71
+
72
+ ### Getting Started
73
+ - **[Installation Guide](getting-started.md)** - Setup and configuration
74
+ - **[Interactive Demo](examples/interactive-demo.md)** - Live code examples
75
+ - **[Code Examples](examples/code-examples.md)** - Complete runnable examples
76
+
77
+ ### Core Concepts
78
+ - **[Entities](core-concepts/entity.md)** - Entity lifecycle and management
79
+ - **[Components](core-concepts/components.md)** - Component definitions and patterns
80
+ - **[ArcheTypes](core-concepts/archetypes.md)** - Entity templates and reuse
81
+ - **[Services](core-concepts/services.md)** - Business logic layer
82
+ - **[Query System](core-concepts/query.md)** - Database querying
83
+ - **[Hooks](core-concepts/hooks.md)** - Lifecycle events and customization
84
+
85
+ ### Advanced Features
86
+ - **[File Uploads](advanced/uploads.md)** - File handling and storage
87
+ - **[Background Tasks](advanced/scheduler.md)** - Job scheduling and processing
88
+ - **[Performance](advanced/performance.md)** - Optimization strategies
89
+ - **[Security](advanced/security.md)** - Authentication and authorization
90
+
91
+ ### API Reference
92
+ - **[Core API](api/core.md)** - Entity, Component, ArcheType classes
93
+ - **[Query API](api/query.md)** - Database operations and querying
94
+ - **[Service API](api/service.md)** - Business logic services
95
+ - **[Hooks API](api/hooks.md)** - Event system and lifecycle
96
+ - **[Upload API](api/upload.md)** - File management
97
+ - **[Scheduler API](api/scheduler.md)** - Background job management
98
+ - **[Performance Guide](api/performance.md)** - Optimization techniques
99
+ - **[Testing Guide](api/testing.md)** - Testing patterns and best practices
100
+
101
+ ## 🌟 Real-World Use Cases
102
+
103
+ BunSane excels in applications requiring:
104
+
105
+ - **Content Management Systems** - Flexible content modeling with components
106
+ - **E-commerce Platforms** - Complex product catalogs with dynamic attributes
107
+ - **Business Applications** - Multi-tenant architectures with customizable entities
108
+ - **Data-Intensive Applications** - Structured data with relationships
109
+
110
+ ## 🤝 Community & Support
111
+
112
+ - **GitHub**: [yaaruu/bunsane](https://github.com/yaaruu/bunsane)
113
+ - **Issues**: [Report bugs or request features](https://github.com/yaaruu/bunsane/issues)
114
+ - **Discussions**: [Community discussions](https://github.com/yaaruu/bunsane/discussions)
115
+
116
+ ## 📈 Project Status
117
+
118
+ **Current Version**: 0.1.0 (Development)
119
+ **Documentation**: ✅ Complete API Reference
120
+ **Status**: Actively developed
121
+ **License**: MIT
122
+
123
+ ### ✅ Implemented Features
124
+ - **Core ECS Architecture**: Entity, Component, ArcheType system
125
+ - **Database Integration**: PostgreSQL with automatic schema management
126
+ - **Query System**: Type-safe database querying
127
+ - **Hook System**: Entity and component lifecycle events
128
+ - **Service Layer**: Business logic organization
129
+ - **Basic GraphQL**: GraphQL integration with static schema
130
+ - **File Upload**: Basic file upload handling
131
+ - **Background Tasks**: Simple task scheduling
132
+ - **Component Registry**: Automatic component discovery
133
+
134
+ ### 🚧 In Development
135
+ - **Advanced GraphQL**: Dynamic schema generation from services
136
+ - **Full-Text Search**: Search capabilities across entities
137
+ - **Real-time Features**: WebSocket support for live updates
138
+ - **Advanced Caching**: Distributed caching strategies
139
+ - **OpenAPI Integration**: Automatic API documentation
140
+
141
+ ### 📋 Planned Features
142
+ - **Custom Component Tables**: Direct column storage instead of JSONB
143
+ - **Filesystem Integration**: Advanced file management
144
+ - **Field Constraints**: Data validation and constraints
145
+ - **OpenAPI Specification**: Automatic API spec generation
146
+
147
+ ---
148
+
149
+ *Ready to build something amazing? Let's get started!* 🚀
@@ -0,0 +1,36 @@
1
+ # BunSane Framework
2
+
3
+ > A batteries-included TypeScript API framework for Bun
4
+
5
+ [Get Started](getting-started.md)
6
+ [GitHub](https://github.com/yaaruu/bunsane)
7
+
8
+ ## 🚀 What is BunSane?
9
+
10
+ BunSane is a modern, high-performance TypeScript framework built on Bun runtime that provides:
11
+
12
+ - **Entity-Component-System (ECS)** architecture for flexible data modeling
13
+ - **Basic GraphQL Integration** with Yoga
14
+ - **PostgreSQL integration** with automatic schema management
15
+ - **Lifecycle hooks** for business logic integration
16
+ - **File upload system** with basic handling
17
+
18
+ ## ⚡ Key Features
19
+
20
+ - **Type-Safe**: Full TypeScript support with compile-time guarantees
21
+ - **Performance Optimized**: Built for speed with Bun's native performance
22
+ - **Component-Based**: Flexible entity composition with reusable components
23
+ - **Hook System**: Event-driven architecture for entity lifecycle
24
+ - **Extensible**: Clean architecture for adding custom functionality
25
+
26
+
27
+ ## 🎯 Perfect For
28
+
29
+ - **API Development**: REST and basic GraphQL API creation
30
+ - **Data-Intensive Applications**: Efficient entity management
31
+ - **Content Management**: Basic file upload and handling
32
+ - **Business Applications**: Structured data with relationships
33
+
34
+ ---
35
+
36
+ *Built with ❤️ using Bun, TypeScript, and PostgreSQL*
@@ -0,0 +1,23 @@
1
+ - **Getting Started**
2
+ - [Overview](README.md)
3
+ - [Installation](getting-started.md)
4
+ - [Quick Start](getting-started.md#quick-start)
5
+ - [Configuration](getting-started.md#configuration)
6
+
7
+ - **Core Concepts**
8
+ - [Entity System](core-concepts/entity.md)
9
+ - [Components](core-concepts/components.md)
10
+ - [ArcheTypes](core-concepts/archetypes.md)
11
+ - [Services](core-concepts/services.md)
12
+ - [Query System](core-concepts/query.md)
13
+ - [Lifecycle Hooks](core-concepts/hooks.md)
14
+
15
+ - **API Reference**
16
+ - [Core API](api/core.md)
17
+ - [Query API](api/query.md)
18
+ - [Service API](api/service.md)
19
+ - [Hook API](api/hooks.md)
20
+ - [Upload API](api/upload.md)
21
+
22
+ - **Examples & Tutorials**
23
+ - [Code Examples](examples/code-examples.md)