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
@@ -0,0 +1,24 @@
1
+ import type { Plugin } from 'graphql-yoga';
2
+ import { createRequestLoaders } from './RequestLoaders';
3
+ import type { RequestLoaders } from './RequestLoaders';
4
+ import db from '../database';
5
+
6
+ declare module 'graphql-yoga' {
7
+ interface Context {
8
+ locals: {
9
+ loaders: RequestLoaders;
10
+ requestId: string;
11
+ };
12
+ }
13
+ }
14
+
15
+ export function createRequestContextPlugin(): Plugin {
16
+ return {
17
+ onExecute: ({ args }) => {
18
+ (args as any).contextValue.locals = {
19
+ loaders: createRequestLoaders(db),
20
+ requestId: crypto.randomUUID(),
21
+ };
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,89 @@
1
+ import DataLoader from 'dataloader';
2
+ import { Entity } from './Entity';
3
+ import db from '../database';
4
+ import { inList } from '../database/sqlHelpers';
5
+
6
+ export type ComponentData = {
7
+ typeId: number;
8
+ data: any;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ deletedAt: Date | null;
12
+ };
13
+
14
+ export type RequestLoaders = {
15
+ entityById: DataLoader<string, Entity | null>;
16
+ componentsByEntityType: DataLoader<{ entityId: string; typeId: number }, ComponentData | null>;
17
+ };
18
+
19
+ export function createRequestLoaders(db: any): RequestLoaders {
20
+ const entityById = new DataLoader<string, Entity | null>(async (ids: readonly string[]) => {
21
+ const startTime = Date.now();
22
+ try {
23
+ const uniqueIds = [...new Set(ids)];
24
+ const rows = await db`
25
+ SELECT id
26
+ FROM entities
27
+ WHERE id IN ${inList(uniqueIds, 1)}
28
+ AND deleted_at IS NULL
29
+ `;
30
+ const entities = rows.map((row: any) => {
31
+ const entity = new Entity(row.id);
32
+ entity.setPersisted(true);
33
+ return entity;
34
+ });
35
+ const map = new Map<string, Entity>();
36
+ entities.forEach((e: Entity) => map.set(e.id, e));
37
+
38
+ const duration = Date.now() - startTime;
39
+ if (duration > 1000) { // Log slow queries
40
+ console.warn(`Slow entityById query: ${duration}ms for ${ids.length} entities`);
41
+ }
42
+
43
+ return ids.map(id => map.get(id) ?? null);
44
+ } catch (error) {
45
+ console.error(`Error in entityById DataLoader:`, error);
46
+ throw error;
47
+ }
48
+ });
49
+
50
+ const componentsByEntityType = new DataLoader<{ entityId: string; typeId: number }, ComponentData | null>(
51
+ async (keys: readonly { entityId: string; typeId: number }[]) => {
52
+ const startTime = Date.now();
53
+ try {
54
+ const entityIds = [...new Set(keys.map(k => k.entityId))];
55
+ const typeIds = [...new Set(keys.map(k => k.typeId))];
56
+ const rows = await db`
57
+ SELECT entity_id, type_id, data, created_at, updated_at, deleted_at
58
+ FROM components
59
+ WHERE entity_id IN ${inList(entityIds, 1)}
60
+ AND type_id IN ${inList(typeIds, entityIds.length + 1)}
61
+ AND deleted_at IS NULL
62
+ `;
63
+ const map = new Map<string, ComponentData>();
64
+ rows.forEach((row: any) => {
65
+ const key = `${row.entity_id}-${row.type_id}`;
66
+ map.set(key, {
67
+ typeId: row.type_id,
68
+ data: row.data,
69
+ createdAt: row.created_at,
70
+ updatedAt: row.updated_at,
71
+ deletedAt: row.deleted_at,
72
+ });
73
+ });
74
+
75
+ const duration = Date.now() - startTime;
76
+ if (duration > 1000) { // Log slow queries
77
+ console.warn(`Slow componentsByEntityType query: ${duration}ms for ${keys.length} keys`);
78
+ }
79
+
80
+ return keys.map(k => map.get(`${k.entityId}-${k.typeId}`) ?? null);
81
+ } catch (error) {
82
+ console.error(`Error in componentsByEntityType DataLoader:`, error);
83
+ throw error;
84
+ }
85
+ }
86
+ );
87
+
88
+ return { entityById, componentsByEntityType };
89
+ }