bunsane 0.1.2 → 0.1.4

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 (49) hide show
  1. package/TODO.md +1 -1
  2. package/bun.lock +156 -150
  3. package/core/App.ts +188 -31
  4. package/core/ArcheType.ts +1044 -26
  5. package/core/ComponentRegistry.ts +172 -29
  6. package/core/Components.ts +102 -24
  7. package/core/Decorators.ts +0 -1
  8. package/core/Entity.ts +55 -7
  9. package/core/EntityInterface.ts +4 -0
  10. package/core/EntityManager.ts +4 -4
  11. package/core/Query.ts +169 -3
  12. package/core/RequestLoaders.ts +101 -12
  13. package/core/SchedulerManager.ts +3 -4
  14. package/core/metadata/definitions/ArcheType.ts +9 -0
  15. package/core/metadata/definitions/Component.ts +16 -0
  16. package/core/metadata/definitions/gqlObject.ts +10 -0
  17. package/core/metadata/getMetadataStorage.ts +14 -0
  18. package/core/metadata/index.ts +17 -0
  19. package/core/metadata/metadata-storage.ts +81 -0
  20. package/database/DatabaseHelper.ts +22 -20
  21. package/database/index.ts +6 -1
  22. package/database/sqlHelpers.ts +0 -2
  23. package/gql/ArchetypeOperations.ts +281 -0
  24. package/gql/Generator.ts +252 -62
  25. package/gql/helpers.ts +5 -5
  26. package/gql/index.ts +19 -17
  27. package/gql/types.ts +58 -11
  28. package/index.ts +93 -82
  29. package/package.json +39 -37
  30. package/plugins/index.ts +13 -0
  31. package/scheduler/index.ts +87 -0
  32. package/service/Service.ts +4 -0
  33. package/service/ServiceRegistry.ts +5 -1
  34. package/service/index.ts +1 -1
  35. package/swagger/decorators.ts +65 -0
  36. package/swagger/generator.ts +100 -0
  37. package/swagger/index.ts +2 -0
  38. package/tests/bench/insert.bench.ts +1 -0
  39. package/tests/bench/relations.bench.ts +1 -0
  40. package/tests/bench/sorting.bench.ts +1 -0
  41. package/tests/component-hooks-simple.test.ts +117 -0
  42. package/tests/component-hooks.test.ts +83 -31
  43. package/tests/component.test.ts +1 -0
  44. package/tests/hooks.test.ts +1 -0
  45. package/tests/query.test.ts +46 -4
  46. package/tests/relations.test.ts +1 -0
  47. package/types/app.types.ts +0 -0
  48. package/upload/index.ts +0 -2
  49. package/core/processors/ImageProcessor.ts +0 -423
@@ -0,0 +1,281 @@
1
+ import { getAllArchetypeSchemas, getArchetypeSchema } from "../core/ArcheType";
2
+ import { logger as MainLogger } from "../core/Logger";
3
+
4
+ const logger = MainLogger.child({ scope: "ArchetypeOperations" });
5
+
6
+ export interface ArchetypeOperationConfig {
7
+ enableQueries?: {
8
+ get?: boolean; // getArchetypeName(id: ID!)
9
+ list?: boolean; // listArchetypeNames(filter, limit, offset)
10
+ };
11
+ enableMutations?: {
12
+ create?: boolean; // createArchetypeName(input)
13
+ update?: boolean; // updateArchetypeName(id, input)
14
+ delete?: boolean; // deleteArchetypeName(id)
15
+ };
16
+ }
17
+
18
+ /**
19
+ * Generate GraphQL Query and Mutation fields for archetypes
20
+ * This uses the cached archetype schemas to create CRUD operations
21
+ */
22
+ export function generateArchetypeOperations(config: ArchetypeOperationConfig = {}) {
23
+ const {
24
+ enableQueries = { get: true, list: true },
25
+ enableMutations = { create: true, update: true, delete: true }
26
+ } = config;
27
+
28
+ const schemas = getAllArchetypeSchemas();
29
+ logger.trace(`getAllArchetypeSchemas returned ${schemas.length} schemas`);
30
+
31
+ let typeDefs = "\n# Auto-generated Archetype Types\n";
32
+ const queryFields: string[] = [];
33
+ const mutationFields: string[] = [];
34
+ const resolvers: any = { Query: {}, Mutation: {} };
35
+
36
+ // Track defined types to prevent duplicates
37
+ const definedTypes = new Set<string>();
38
+
39
+ schemas.forEach(({ zodSchema, graphqlSchema }) => {
40
+ // Extract archetype name from the schema
41
+ const archetypeName = extractArchetypeName(graphqlSchema);
42
+ if (!archetypeName) {
43
+ logger.warn(`Could not extract archetype name from schema: ${graphqlSchema.substring(0, 100)}`);
44
+ return;
45
+ }
46
+
47
+ logger.trace(`Generating operations for archetype: ${archetypeName}`);
48
+
49
+ // Add the archetype type definition (without Query/Mutation)
50
+ // Extract and deduplicate type definitions
51
+ const typeDefinitions = extractTypeDefinitions(graphqlSchema);
52
+ const deduplicatedTypes = deduplicateTypeDefinitions(typeDefinitions, definedTypes);
53
+ logger.trace(`Adding ${deduplicatedTypes.length} characters of type definitions for ${archetypeName}`);
54
+ typeDefs += deduplicatedTypes;
55
+ });
56
+
57
+ typeDefs += "\n# END AUTO-GENERATED TYPES\n";
58
+ logger.trace(`Final typeDefs length: ${typeDefs.length}`);
59
+
60
+ // Return types only, without operations
61
+ return { typeDefs, queryFields, mutationFields, resolvers };
62
+ }
63
+
64
+ /**
65
+ * WIP
66
+ * Generate full archetype operations including types, queries, and mutations
67
+ */
68
+ //TODO: Implement this
69
+ export function generateArchetypeOperationsWithCRUD(config: ArchetypeOperationConfig = {}) {
70
+ const {
71
+ enableQueries = { get: true, list: true },
72
+ enableMutations = { create: true, update: true, delete: true }
73
+ } = config;
74
+
75
+ const schemas = getAllArchetypeSchemas();
76
+ let typeDefs = "\n# Auto-generated Archetype Types\n";
77
+ const queryFields: string[] = [];
78
+ const mutationFields: string[] = [];
79
+ const resolvers: any = { Query: {}, Mutation: {} };
80
+
81
+ schemas.forEach(({ zodSchema, graphqlSchema }) => {
82
+ // Extract archetype name from the schema
83
+ const archetypeName = extractArchetypeName(graphqlSchema);
84
+ if (!archetypeName) return;
85
+
86
+ logger.trace(`Generating operations for archetype: ${archetypeName}`);
87
+
88
+ // Add the archetype type definition (without Query/Mutation)
89
+ typeDefs += extractTypeDefinitions(graphqlSchema);
90
+
91
+ // Generate filter input type
92
+ typeDefs += generateFilterInput(archetypeName, zodSchema);
93
+
94
+ // Generate create input type
95
+ typeDefs += generateCreateInput(archetypeName, zodSchema);
96
+
97
+ // Generate update input type
98
+ typeDefs += generateUpdateInput(archetypeName, zodSchema);
99
+
100
+ // Generate Query operations
101
+ if (enableQueries?.get) {
102
+ queryFields.push(`get${archetypeName}(id: ID!): ${archetypeName}`);
103
+ resolvers.Query[`get${archetypeName}`] = createGetResolver(archetypeName);
104
+ }
105
+
106
+ if (enableQueries?.list) {
107
+ queryFields.push(`list${archetypeName}s(filter: ${archetypeName}Filter, limit: Int, offset: Int): [${archetypeName}!]!`);
108
+ resolvers.Query[`list${archetypeName}s`] = createListResolver(archetypeName);
109
+ }
110
+
111
+ // Generate Mutation operations
112
+ if (enableMutations?.create) {
113
+ mutationFields.push(`create${archetypeName}(input: Create${archetypeName}Input!): ${archetypeName}!`);
114
+ resolvers.Mutation[`create${archetypeName}`] = createCreateResolver(archetypeName);
115
+ }
116
+
117
+ if (enableMutations?.update) {
118
+ mutationFields.push(`update${archetypeName}(id: ID!, input: Update${archetypeName}Input!): ${archetypeName}!`);
119
+ resolvers.Mutation[`update${archetypeName}`] = createUpdateResolver(archetypeName);
120
+ }
121
+
122
+ if (enableMutations?.delete) {
123
+ mutationFields.push(`delete${archetypeName}(id: ID!): Boolean!`);
124
+ resolvers.Mutation[`delete${archetypeName}`] = createDeleteResolver(archetypeName);
125
+ }
126
+ });
127
+
128
+ return { typeDefs, queryFields, mutationFields, resolvers };
129
+ }
130
+
131
+ function extractArchetypeName(graphqlSchema: string): string | null {
132
+ const match = graphqlSchema.match(/type (\w+) \{/);
133
+ return match ? match[1] ?? null : null;
134
+ }
135
+
136
+ function extractTypeDefinitions(graphqlSchema: string): string {
137
+ // Remove Query and Mutation types, keep only object types and enums
138
+ const lines = graphqlSchema.split('\n');
139
+ const filtered = lines.filter(line => {
140
+ const trimmed = line.trim();
141
+ return !trimmed.startsWith('type Query') &&
142
+ !trimmed.startsWith('type Mutation') &&
143
+ !trimmed.startsWith('type Subscription');
144
+ });
145
+ return filtered.join('\n') + '\n';
146
+ }
147
+
148
+ /**
149
+ * Deduplicates type definitions by tracking which types have already been defined.
150
+ * Parses the type definitions and only returns new ones.
151
+ */
152
+ function deduplicateTypeDefinitions(typeDefinitions: string, definedTypes: Set<string>): string {
153
+ const lines = typeDefinitions.split('\n');
154
+ const result: string[] = [];
155
+ let currentType = '';
156
+ let currentTypeName = '';
157
+ let inTypeDefinition = false;
158
+
159
+ for (const line of lines) {
160
+ const trimmed = line.trim();
161
+
162
+ // Check if this is the start of a type/enum/input definition
163
+ const typeMatch = trimmed.match(/^(type|enum|input)\s+(\w+)/);
164
+
165
+ if (typeMatch) {
166
+ // Save previous type if we were in one
167
+ if (inTypeDefinition && currentTypeName && !definedTypes.has(currentTypeName)) {
168
+ result.push(currentType);
169
+ definedTypes.add(currentTypeName);
170
+ }
171
+
172
+ // Start new type
173
+ currentTypeName = typeMatch[2] || '';
174
+ currentType = line + '\n';
175
+ inTypeDefinition = true;
176
+ } else if (inTypeDefinition) {
177
+ currentType += line + '\n';
178
+
179
+ // Check if this is the closing brace
180
+ if (trimmed === '}') {
181
+ // End of type definition
182
+ if (!definedTypes.has(currentTypeName)) {
183
+ result.push(currentType);
184
+ definedTypes.add(currentTypeName);
185
+ logger.trace(`Added type definition: ${currentTypeName}`);
186
+ } else {
187
+ logger.trace(`Skipped duplicate type definition: ${currentTypeName}`);
188
+ }
189
+ currentType = '';
190
+ currentTypeName = '';
191
+ inTypeDefinition = false;
192
+ }
193
+ } else {
194
+ // Not in a type definition, just add the line (could be comments, etc.)
195
+ result.push(line + '\n');
196
+ }
197
+ }
198
+
199
+ // Handle last type if file doesn't end with closing brace
200
+ if (inTypeDefinition && currentTypeName && !definedTypes.has(currentTypeName)) {
201
+ result.push(currentType);
202
+ definedTypes.add(currentTypeName);
203
+ }
204
+
205
+ return result.join('');
206
+ }
207
+
208
+ function generateFilterInput(archetypeName: string, zodSchema: any): string {
209
+ // Generate filter input with common filter operators
210
+ // Add a dummy field to make the input type valid until full implementation
211
+ return `
212
+ input ${archetypeName}Filter {
213
+ id: ID
214
+ _placeholder: String
215
+ }
216
+
217
+ `;
218
+ }
219
+
220
+ function generateCreateInput(archetypeName: string, zodSchema: any): string {
221
+ // Generate create input (all fields except id)
222
+ // Add a dummy field to make the input type valid until full implementation
223
+ return `
224
+ input Create${archetypeName}Input {
225
+ _placeholder: String
226
+ }
227
+
228
+ `;
229
+ }
230
+
231
+ function generateUpdateInput(archetypeName: string, zodSchema: any): string {
232
+ // Generate update input (all fields optional except id)
233
+ // Add a dummy field to make the input type valid until full implementation
234
+ return `
235
+ input Update${archetypeName}Input {
236
+ _placeholder: String
237
+ }
238
+
239
+ `;
240
+ }
241
+
242
+ // Resolver creators
243
+ function createGetResolver(archetypeName: string) {
244
+ return async (_: any, { id }: { id: string }, context: any) => {
245
+ // TODO: Implement actual entity fetching
246
+ logger.trace(`Getting ${archetypeName} with id: ${id}`);
247
+ throw new Error(`get${archetypeName} resolver not implemented`);
248
+ };
249
+ }
250
+
251
+ function createListResolver(archetypeName: string) {
252
+ return async (_: any, { filter, limit, offset }: any, context: any) => {
253
+ // TODO: Implement actual entity querying
254
+ logger.trace(`Listing ${archetypeName}s with filter:`, filter);
255
+ throw new Error(`list${archetypeName}s resolver not implemented`);
256
+ };
257
+ }
258
+
259
+ function createCreateResolver(archetypeName: string) {
260
+ return async (_: any, { input }: any, context: any) => {
261
+ // TODO: Implement actual entity creation
262
+ logger.trace(`Creating ${archetypeName} with input:`, input);
263
+ throw new Error(`create${archetypeName} resolver not implemented`);
264
+ };
265
+ }
266
+
267
+ function createUpdateResolver(archetypeName: string) {
268
+ return async (_: any, { id, input }: any, context: any) => {
269
+ // TODO: Implement actual entity update
270
+ logger.trace(`Updating ${archetypeName} ${id} with input:`, input);
271
+ throw new Error(`update${archetypeName} resolver not implemented`);
272
+ };
273
+ }
274
+
275
+ function createDeleteResolver(archetypeName: string) {
276
+ return async (_: any, { id }: { id: string }, context: any) => {
277
+ // TODO: Implement actual entity deletion
278
+ logger.trace(`Deleting ${archetypeName} with id: ${id}`);
279
+ throw new Error(`delete${archetypeName} resolver not implemented`);
280
+ };
281
+ }