bunsane 0.1.0 → 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.
- package/.github/workflows/deploy-docs.yml +57 -0
- package/LICENSE.md +1 -1
- package/README.md +2 -28
- package/TODO.md +8 -1
- package/bun.lock +3 -0
- package/config/upload.config.ts +135 -0
- package/core/App.ts +119 -4
- package/core/ArcheType.ts +122 -0
- package/core/BatchLoader.ts +100 -0
- package/core/ComponentRegistry.ts +4 -3
- package/core/Components.ts +2 -2
- package/core/Decorators.ts +15 -8
- package/core/Entity.ts +159 -12
- package/core/EntityCache.ts +15 -0
- package/core/EntityHookManager.ts +855 -0
- package/core/EntityManager.ts +12 -2
- package/core/ErrorHandler.ts +64 -7
- package/core/FileValidator.ts +284 -0
- package/core/Query.ts +453 -85
- package/core/RequestContext.ts +24 -0
- package/core/RequestLoaders.ts +65 -0
- package/core/SchedulerManager.ts +710 -0
- package/core/UploadManager.ts +261 -0
- package/core/components/UploadComponent.ts +206 -0
- package/core/decorators/EntityHooks.ts +190 -0
- package/core/decorators/ScheduledTask.ts +83 -0
- package/core/events/EntityLifecycleEvents.ts +177 -0
- package/core/processors/ImageProcessor.ts +423 -0
- package/core/storage/LocalStorageProvider.ts +290 -0
- package/core/storage/StorageProvider.ts +112 -0
- package/database/DatabaseHelper.ts +183 -58
- package/database/index.ts +1 -1
- package/database/sqlHelpers.ts +7 -0
- package/docs/README.md +149 -0
- package/docs/_coverpage.md +36 -0
- package/docs/_sidebar.md +23 -0
- package/docs/api/core.md +568 -0
- package/docs/api/hooks.md +554 -0
- package/docs/api/index.md +222 -0
- package/docs/api/query.md +678 -0
- package/docs/api/service.md +744 -0
- package/docs/core-concepts/archetypes.md +512 -0
- package/docs/core-concepts/components.md +498 -0
- package/docs/core-concepts/entity.md +314 -0
- package/docs/core-concepts/hooks.md +683 -0
- package/docs/core-concepts/query.md +588 -0
- package/docs/core-concepts/services.md +647 -0
- package/docs/examples/code-examples.md +425 -0
- package/docs/getting-started.md +337 -0
- package/docs/index.html +97 -0
- package/examples/hooks/README.md +228 -0
- package/examples/hooks/audit-logger.ts +495 -0
- package/gql/Generator.ts +56 -34
- package/gql/decorators/Upload.ts +176 -0
- package/gql/helpers.ts +67 -0
- package/gql/index.ts +55 -31
- package/gql/types.ts +1 -1
- package/index.ts +79 -11
- package/package.json +5 -4
- package/rest/Generator.ts +3 -0
- package/rest/index.ts +22 -0
- package/service/Service.ts +1 -1
- package/service/ServiceRegistry.ts +10 -6
- package/service/index.ts +12 -1
- package/tests/bench/insert.bench.ts +59 -0
- package/tests/bench/relations.bench.ts +269 -0
- package/tests/bench/sorting.bench.ts +415 -0
- package/tests/component-hooks.test.ts +1409 -0
- package/tests/component.test.ts +205 -0
- package/tests/errorHandling.test.ts +155 -0
- package/tests/hooks.test.ts +666 -0
- package/tests/query-sorting.test.ts +101 -0
- package/tests/relations.test.ts +169 -0
- package/tests/scheduler.test.ts +724 -0
- package/tsconfig.json +35 -34
- package/types/graphql.types.ts +87 -0
- package/types/hooks.types.ts +141 -0
- package/types/scheduler.types.ts +165 -0
- package/types/upload.types.ts +184 -0
- package/upload/index.ts +140 -0
- package/utils/UploadHelper.ts +305 -0
- package/utils/cronParser.ts +366 -0
- package/utils/errorMessages.ts +151 -0
- package/validate-docs.sh +90 -0
- package/core/Events.ts +0 -0
package/tsconfig.json
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
|
|
11
|
-
// Bundler mode
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true,
|
|
14
|
-
"verbatimModuleSyntax": true,
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Path mappings for internal modules
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
// Best practices
|
|
20
|
+
"strict": true,
|
|
21
|
+
"skipLibCheck": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noUncheckedIndexedAccess": true,
|
|
24
|
+
"noImplicitOverride": true,
|
|
25
|
+
|
|
26
|
+
// Some stricter flags (disabled by default)
|
|
27
|
+
"noUnusedLocals": false,
|
|
28
|
+
"noUnusedParameters": false,
|
|
29
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
30
|
+
|
|
31
|
+
"experimentalDecorators": true,
|
|
32
|
+
"emitDecoratorMetadata": true,
|
|
33
|
+
"typeRoots": ["./types", "./node_modules/@types"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// GraphQL Type Definitions for Bunsane Framework
|
|
2
|
+
// This file provides basic type safety for GraphQL resolvers and context
|
|
3
|
+
|
|
4
|
+
import { Entity } from "../core/Entity";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Basic GraphQL Context interface
|
|
8
|
+
* Provides common properties used in resolvers
|
|
9
|
+
* Applications can extend this interface to add their own context properties
|
|
10
|
+
*/
|
|
11
|
+
export interface GraphQLContext {
|
|
12
|
+
/** The incoming HTTP request */
|
|
13
|
+
request?: Request;
|
|
14
|
+
/** Additional context properties can be added by applications */
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Simplified GraphQL Info type
|
|
20
|
+
* Represents the GraphQLResolveInfo with minimal properties for type safety
|
|
21
|
+
*/
|
|
22
|
+
export interface GraphQLInfo {
|
|
23
|
+
/** The field name being resolved */
|
|
24
|
+
fieldName: string;
|
|
25
|
+
/** The field nodes in the selection set */
|
|
26
|
+
fieldNodes: any[];
|
|
27
|
+
/** The return type of the field */
|
|
28
|
+
returnType: any;
|
|
29
|
+
/** The parent type */
|
|
30
|
+
parentType: any;
|
|
31
|
+
/** The schema */
|
|
32
|
+
schema: any;
|
|
33
|
+
/** Fragments defined in the query */
|
|
34
|
+
fragments: any;
|
|
35
|
+
/** Root value */
|
|
36
|
+
rootValue: any;
|
|
37
|
+
/** Operation */
|
|
38
|
+
operation: any;
|
|
39
|
+
/** Variable values */
|
|
40
|
+
variableValues: any;
|
|
41
|
+
/** Path to the current field */
|
|
42
|
+
path: any;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Utility type for resolver functions
|
|
47
|
+
* Simplifies resolver signatures by hiding complex generics
|
|
48
|
+
*/
|
|
49
|
+
export type SimpleResolver<TArgs = any, TReturn = any> = (
|
|
50
|
+
args: TArgs,
|
|
51
|
+
context: GraphQLContext,
|
|
52
|
+
info: GraphQLInfo
|
|
53
|
+
) => TReturn | Promise<TReturn>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Utility type for field resolvers
|
|
57
|
+
* Provides type safety for parent entity and common parameters
|
|
58
|
+
*/
|
|
59
|
+
export type FieldResolver<TParent = Entity, TArgs = any, TReturn = any> = (
|
|
60
|
+
parent: TParent,
|
|
61
|
+
args: TArgs,
|
|
62
|
+
context: GraphQLContext,
|
|
63
|
+
info: GraphQLInfo
|
|
64
|
+
) => TReturn | Promise<TReturn>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Branded type for better error messages
|
|
68
|
+
*/
|
|
69
|
+
export type BrandedString<T extends string> = string & { __brand: T };
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Schema-aware GraphQL operation type
|
|
73
|
+
*/
|
|
74
|
+
export type SchemaOperation<TInput, TOutput> = {
|
|
75
|
+
type: "Query" | "Mutation";
|
|
76
|
+
input: TInput;
|
|
77
|
+
output: TOutput;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Type-safe resolver with schema awareness
|
|
82
|
+
*/
|
|
83
|
+
export type SchemaResolver<TInput, TOutput> = (
|
|
84
|
+
args: TInput,
|
|
85
|
+
context: GraphQLContext,
|
|
86
|
+
info: GraphQLInfo
|
|
87
|
+
) => TOutput | Promise<TOutput>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Entity Lifecycle Hooks system
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Entity } from "../core/Entity";
|
|
6
|
+
import type { BaseComponent } from "../core/Components";
|
|
7
|
+
import type {
|
|
8
|
+
EntityEvent,
|
|
9
|
+
ComponentEvent,
|
|
10
|
+
LifecycleEvent,
|
|
11
|
+
EntityCreatedEvent,
|
|
12
|
+
EntityUpdatedEvent,
|
|
13
|
+
EntityDeletedEvent,
|
|
14
|
+
ComponentAddedEvent,
|
|
15
|
+
ComponentUpdatedEvent,
|
|
16
|
+
ComponentRemovedEvent
|
|
17
|
+
} from "../core/events/EntityLifecycleEvents";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hook callback function signature for entity events
|
|
21
|
+
*/
|
|
22
|
+
export type EntityHookCallback<T extends EntityEvent = EntityEvent> = (event: T) => void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Hook callback function signature for component events
|
|
26
|
+
*/
|
|
27
|
+
export type ComponentHookCallback<T extends ComponentEvent = ComponentEvent> = (event: T) => void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Hook callback function signature for any lifecycle event
|
|
31
|
+
*/
|
|
32
|
+
export type LifecycleHookCallback = (event: LifecycleEvent) => void;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Hook registration options
|
|
36
|
+
*/
|
|
37
|
+
export interface HookOptions {
|
|
38
|
+
/** Priority for hook execution order (higher numbers execute first) */
|
|
39
|
+
priority?: number;
|
|
40
|
+
/** Optional name for the hook for debugging */
|
|
41
|
+
name?: string;
|
|
42
|
+
/** Whether the hook should be executed asynchronously */
|
|
43
|
+
async?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Hook execution context
|
|
48
|
+
*/
|
|
49
|
+
export interface HookContext {
|
|
50
|
+
/** The entity associated with the event */
|
|
51
|
+
entity: Entity;
|
|
52
|
+
/** The event that triggered the hook */
|
|
53
|
+
event: LifecycleEvent;
|
|
54
|
+
/** Timestamp when the hook execution started */
|
|
55
|
+
executionStart: Date;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Hook execution result
|
|
60
|
+
*/
|
|
61
|
+
export interface HookResult {
|
|
62
|
+
/** Whether the hook executed successfully */
|
|
63
|
+
success: boolean;
|
|
64
|
+
/** Execution time in milliseconds */
|
|
65
|
+
executionTime: number;
|
|
66
|
+
/** Error if execution failed */
|
|
67
|
+
error?: Error;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Batch hook execution result
|
|
72
|
+
*/
|
|
73
|
+
export interface BatchHookResult {
|
|
74
|
+
/** Total number of hooks executed */
|
|
75
|
+
totalHooks: number;
|
|
76
|
+
/** Number of successful executions */
|
|
77
|
+
successful: number;
|
|
78
|
+
/** Number of failed executions */
|
|
79
|
+
failed: number;
|
|
80
|
+
/** Total execution time */
|
|
81
|
+
totalExecutionTime: number;
|
|
82
|
+
/** Individual hook results */
|
|
83
|
+
results: HookResult[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Hook filter function for conditional execution
|
|
88
|
+
*/
|
|
89
|
+
export type HookFilter<T extends LifecycleEvent = LifecycleEvent> = (event: T) => boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Filtered hook registration options
|
|
93
|
+
*/
|
|
94
|
+
export interface FilteredHookOptions extends HookOptions {
|
|
95
|
+
/** Filter function to determine if hook should execute */
|
|
96
|
+
filter?: HookFilter;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Hook metadata for introspection
|
|
101
|
+
*/
|
|
102
|
+
export interface HookMetadata {
|
|
103
|
+
/** Unique hook identifier */
|
|
104
|
+
id: string;
|
|
105
|
+
/** Event type the hook is registered for */
|
|
106
|
+
eventType: string;
|
|
107
|
+
/** Hook name for debugging */
|
|
108
|
+
name?: string;
|
|
109
|
+
/** Hook priority */
|
|
110
|
+
priority: number;
|
|
111
|
+
/** Whether hook executes asynchronously */
|
|
112
|
+
async: boolean;
|
|
113
|
+
/** Registration timestamp */
|
|
114
|
+
registeredAt: Date;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Hook manager statistics
|
|
119
|
+
*/
|
|
120
|
+
export interface HookStats {
|
|
121
|
+
/** Total number of registered hooks */
|
|
122
|
+
totalHooks: number;
|
|
123
|
+
/** Number of hooks by event type */
|
|
124
|
+
hooksByEventType: Record<string, number>;
|
|
125
|
+
/** Average execution time per event type */
|
|
126
|
+
averageExecutionTime: Record<string, number>;
|
|
127
|
+
/** Error rate per event type */
|
|
128
|
+
errorRate: Record<string, number>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Hook execution options for advanced scenarios
|
|
133
|
+
*/
|
|
134
|
+
export interface HookExecutionOptions {
|
|
135
|
+
/** Timeout for hook execution in milliseconds */
|
|
136
|
+
timeout?: number;
|
|
137
|
+
/** Whether to continue executing other hooks if one fails */
|
|
138
|
+
continueOnError?: boolean;
|
|
139
|
+
/** Maximum number of hooks to execute in parallel */
|
|
140
|
+
maxConcurrency?: number;
|
|
141
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Scheduler Type Definitions
|
|
3
|
+
* Comprehensive TypeScript types for the BunSane scheduler system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { QueryFilter } from "../core/Query";
|
|
7
|
+
import type { ComponentTargetConfig } from "../core/EntityHookManager";
|
|
8
|
+
|
|
9
|
+
export enum ScheduleInterval {
|
|
10
|
+
MINUTE = "minute",
|
|
11
|
+
HOUR = "hour",
|
|
12
|
+
DAILY = "daily",
|
|
13
|
+
WEEKLY = "weekly",
|
|
14
|
+
MONTHLY = "monthly",
|
|
15
|
+
CRON = "cron"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ScheduledTaskOptions {
|
|
19
|
+
/** Unique identifier for the task */
|
|
20
|
+
id?: string;
|
|
21
|
+
/** Human-readable name for the task */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Whether the task should run immediately on startup */
|
|
24
|
+
runOnStart?: boolean;
|
|
25
|
+
/** Maximum execution time in milliseconds */
|
|
26
|
+
timeout?: number;
|
|
27
|
+
/** Whether to enable logging for this task */
|
|
28
|
+
enableLogging?: boolean;
|
|
29
|
+
/** Priority for execution ordering (higher numbers execute first) */
|
|
30
|
+
priority?: number;
|
|
31
|
+
/** Maximum retry attempts for failed tasks */
|
|
32
|
+
maxRetries?: number;
|
|
33
|
+
/** Delay between retry attempts in milliseconds */
|
|
34
|
+
retryDelay?: number;
|
|
35
|
+
/** Whether to continue retrying on failure */
|
|
36
|
+
continueOnError?: boolean;
|
|
37
|
+
/** Query filters to apply when querying components */
|
|
38
|
+
componentFilters?: QueryFilter[];
|
|
39
|
+
/** Maximum number of entities to process per execution */
|
|
40
|
+
maxEntitiesPerExecution?: number;
|
|
41
|
+
/** Whether to enable task metrics collection */
|
|
42
|
+
enableMetrics?: boolean;
|
|
43
|
+
/** Component targeting configuration for fine-grained entity selection */
|
|
44
|
+
componentTarget?: ComponentTargetConfig;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ScheduledTaskInfo {
|
|
48
|
+
/** Unique task identifier */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Task name */
|
|
51
|
+
name: string;
|
|
52
|
+
/** Target component class (legacy - use options.componentTarget instead) */
|
|
53
|
+
componentTarget?: new (...args: any[]) => any;
|
|
54
|
+
/** Schedule interval */
|
|
55
|
+
interval: ScheduleInterval;
|
|
56
|
+
/** Cron expression (when interval is CRON) */
|
|
57
|
+
cronExpression?: string;
|
|
58
|
+
/** Task options */
|
|
59
|
+
options: ScheduledTaskOptions;
|
|
60
|
+
/** Service instance */
|
|
61
|
+
service: any;
|
|
62
|
+
/** Method name to execute */
|
|
63
|
+
methodName: string;
|
|
64
|
+
/** Next execution timestamp */
|
|
65
|
+
nextExecution: Date;
|
|
66
|
+
/** Last execution timestamp */
|
|
67
|
+
lastExecution?: Date;
|
|
68
|
+
/** Execution count */
|
|
69
|
+
executionCount: number;
|
|
70
|
+
/** Whether task is currently running */
|
|
71
|
+
isRunning: boolean;
|
|
72
|
+
/** Whether task is enabled */
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
/** Priority for execution ordering (higher numbers execute first) */
|
|
75
|
+
priority?: number;
|
|
76
|
+
/** Maximum retry attempts */
|
|
77
|
+
maxRetries?: number;
|
|
78
|
+
/** Current retry count */
|
|
79
|
+
retryCount?: number;
|
|
80
|
+
/** Last error message */
|
|
81
|
+
lastError?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SchedulerMetrics {
|
|
85
|
+
/** Total number of registered tasks */
|
|
86
|
+
totalTasks: number;
|
|
87
|
+
/** Number of currently running tasks */
|
|
88
|
+
runningTasks: number;
|
|
89
|
+
/** Number of completed executions */
|
|
90
|
+
completedExecutions: number;
|
|
91
|
+
/** Number of failed executions */
|
|
92
|
+
failedExecutions: number;
|
|
93
|
+
/** Average execution time in milliseconds */
|
|
94
|
+
averageExecutionTime: number;
|
|
95
|
+
/** Total execution time in milliseconds */
|
|
96
|
+
totalExecutionTime: number;
|
|
97
|
+
/** Number of timed out tasks */
|
|
98
|
+
timedOutTasks: number;
|
|
99
|
+
/** Number of retried tasks */
|
|
100
|
+
retriedTasks: number;
|
|
101
|
+
/** Task-specific metrics */
|
|
102
|
+
taskMetrics: Record<string, TaskMetrics>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface TaskMetrics {
|
|
106
|
+
/** Task ID */
|
|
107
|
+
taskId: string;
|
|
108
|
+
/** Task name */
|
|
109
|
+
taskName: string;
|
|
110
|
+
/** Total executions */
|
|
111
|
+
totalExecutions: number;
|
|
112
|
+
/** Successful executions */
|
|
113
|
+
successfulExecutions: number;
|
|
114
|
+
/** Failed executions */
|
|
115
|
+
failedExecutions: number;
|
|
116
|
+
/** Average execution time */
|
|
117
|
+
averageExecutionTime: number;
|
|
118
|
+
/** Last execution time */
|
|
119
|
+
lastExecutionTime?: Date;
|
|
120
|
+
/** Total entities processed */
|
|
121
|
+
totalEntitiesProcessed: number;
|
|
122
|
+
/** Retry count */
|
|
123
|
+
retryCount: number;
|
|
124
|
+
/** Timeout count */
|
|
125
|
+
timeoutCount: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface TaskExecutionResult {
|
|
129
|
+
/** Whether execution was successful */
|
|
130
|
+
success: boolean;
|
|
131
|
+
/** Execution duration in milliseconds */
|
|
132
|
+
duration: number;
|
|
133
|
+
/** Number of entities processed */
|
|
134
|
+
entitiesProcessed: number;
|
|
135
|
+
/** Error message if execution failed */
|
|
136
|
+
error?: string;
|
|
137
|
+
/** Timestamp of execution */
|
|
138
|
+
executedAt: Date;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface SchedulerEvent {
|
|
142
|
+
/** Event type */
|
|
143
|
+
type: 'task.registered' | 'task.executed' | 'task.failed' | 'task.timeout' | 'task.retry' | 'scheduler.started' | 'scheduler.stopped';
|
|
144
|
+
/** Task ID if applicable */
|
|
145
|
+
taskId?: string;
|
|
146
|
+
/** Event timestamp */
|
|
147
|
+
timestamp: Date;
|
|
148
|
+
/** Additional event data */
|
|
149
|
+
data?: any;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type SchedulerEventCallback = (event: SchedulerEvent) => void;
|
|
153
|
+
|
|
154
|
+
export interface SchedulerConfig {
|
|
155
|
+
/** Whether scheduler is enabled */
|
|
156
|
+
enabled: boolean;
|
|
157
|
+
/** Maximum concurrent tasks */
|
|
158
|
+
maxConcurrentTasks: number;
|
|
159
|
+
/** Default task timeout in milliseconds */
|
|
160
|
+
defaultTimeout: number;
|
|
161
|
+
/** Whether to enable detailed logging */
|
|
162
|
+
enableLogging: boolean;
|
|
163
|
+
/** Whether to run tasks on startup */
|
|
164
|
+
runOnStart: boolean;
|
|
165
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload System Type Definitions
|
|
3
|
+
* Comprehensive TypeScript types for the Bunsane upload system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface UploadConfiguration {
|
|
7
|
+
/** Maximum file size in bytes */
|
|
8
|
+
maxFileSize: number;
|
|
9
|
+
|
|
10
|
+
/** Allowed MIME types */
|
|
11
|
+
allowedMimeTypes: string[];
|
|
12
|
+
|
|
13
|
+
/** Allowed file extensions */
|
|
14
|
+
allowedExtensions: string[];
|
|
15
|
+
|
|
16
|
+
/** Validate file signature (magic numbers) */
|
|
17
|
+
validateFileSignature: boolean;
|
|
18
|
+
|
|
19
|
+
/** Sanitize file names to prevent path traversal */
|
|
20
|
+
sanitizeFileName: boolean;
|
|
21
|
+
|
|
22
|
+
/** Preserve original file name */
|
|
23
|
+
preserveOriginalName: boolean;
|
|
24
|
+
|
|
25
|
+
/** Generate thumbnails for images */
|
|
26
|
+
generateThumbnails: boolean;
|
|
27
|
+
|
|
28
|
+
/** Upload path relative to storage root */
|
|
29
|
+
uploadPath: string;
|
|
30
|
+
|
|
31
|
+
/** File naming strategy */
|
|
32
|
+
namingStrategy: "uuid" | "timestamp" | "original";
|
|
33
|
+
|
|
34
|
+
/** Storage provider to use */
|
|
35
|
+
storageProvider?: string;
|
|
36
|
+
|
|
37
|
+
/** Image processing options */
|
|
38
|
+
imageProcessing?: ImageProcessingOptions;
|
|
39
|
+
|
|
40
|
+
/** Validation options */
|
|
41
|
+
validation?: ValidationOptions;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ImageProcessingOptions {
|
|
45
|
+
/** Generate thumbnails */
|
|
46
|
+
generateThumbnails: boolean;
|
|
47
|
+
|
|
48
|
+
/** Thumbnail sizes */
|
|
49
|
+
thumbnailSizes: Array<{ width: number; height: number; suffix: string }>;
|
|
50
|
+
|
|
51
|
+
/** Compress images */
|
|
52
|
+
compress: boolean;
|
|
53
|
+
|
|
54
|
+
/** Compression quality (0-100) */
|
|
55
|
+
quality: number;
|
|
56
|
+
|
|
57
|
+
/** Convert to specific format */
|
|
58
|
+
convertTo?: "jpeg" | "png" | "webp";
|
|
59
|
+
|
|
60
|
+
/** Maximum dimensions */
|
|
61
|
+
maxDimensions?: { width: number; height: number };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ValidationOptions {
|
|
65
|
+
/** Check for malicious files */
|
|
66
|
+
scanForMalware: boolean;
|
|
67
|
+
|
|
68
|
+
/** Custom validation functions */
|
|
69
|
+
customValidators?: Array<(file: File) => Promise<ValidationResult>>;
|
|
70
|
+
|
|
71
|
+
/** Strict MIME type checking */
|
|
72
|
+
strictMimeType: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ValidationResult {
|
|
76
|
+
valid: boolean;
|
|
77
|
+
errors: string[];
|
|
78
|
+
warnings?: string[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface UploadResult {
|
|
82
|
+
success: boolean;
|
|
83
|
+
uploadId?: string;
|
|
84
|
+
fileName?: string;
|
|
85
|
+
originalFileName?: string;
|
|
86
|
+
mimeType?: string;
|
|
87
|
+
size?: number;
|
|
88
|
+
path?: string;
|
|
89
|
+
url?: string;
|
|
90
|
+
metadata?: Record<string, any>;
|
|
91
|
+
thumbnails?: Array<{ size: string; url: string; path: string }>;
|
|
92
|
+
error?: UploadError;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface UploadError {
|
|
96
|
+
uploadId: string;
|
|
97
|
+
code: UploadErrorCode;
|
|
98
|
+
message: string;
|
|
99
|
+
details?: Record<string, any>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type UploadErrorCode =
|
|
103
|
+
| "VALIDATION_FAILED"
|
|
104
|
+
| "FILE_TOO_LARGE"
|
|
105
|
+
| "INVALID_FILE_TYPE"
|
|
106
|
+
| "MALICIOUS_FILE"
|
|
107
|
+
| "UPLOAD_FAILED"
|
|
108
|
+
| "STORAGE_ERROR"
|
|
109
|
+
| "PROCESSING_ERROR"
|
|
110
|
+
| "NETWORK_ERROR"
|
|
111
|
+
| "PERMISSION_DENIED"
|
|
112
|
+
| "QUOTA_EXCEEDED";
|
|
113
|
+
|
|
114
|
+
export interface FileMetadata {
|
|
115
|
+
uploadId: string;
|
|
116
|
+
fileName: string;
|
|
117
|
+
originalFileName: string;
|
|
118
|
+
mimeType: string;
|
|
119
|
+
size: number;
|
|
120
|
+
extension: string;
|
|
121
|
+
uploadedAt: string;
|
|
122
|
+
dimensions?: { width: number; height: number };
|
|
123
|
+
hash?: string;
|
|
124
|
+
userMetadata?: Record<string, any>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface StorageResult {
|
|
128
|
+
path: string;
|
|
129
|
+
url: string;
|
|
130
|
+
metadata?: Record<string, any>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface UploadProgress {
|
|
134
|
+
uploadId: string;
|
|
135
|
+
fileName: string;
|
|
136
|
+
totalBytes: number;
|
|
137
|
+
uploadedBytes: number;
|
|
138
|
+
percentage: number;
|
|
139
|
+
speed?: number;
|
|
140
|
+
remainingTime?: number;
|
|
141
|
+
status: "pending" | "uploading" | "processing" | "completed" | "failed";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface BatchUploadResult {
|
|
145
|
+
totalFiles: number;
|
|
146
|
+
successfulUploads: number;
|
|
147
|
+
failedUploads: number;
|
|
148
|
+
results: UploadResult[];
|
|
149
|
+
errors: UploadError[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface UploadComponentData {
|
|
153
|
+
uploadId: string;
|
|
154
|
+
fileName: string;
|
|
155
|
+
originalFileName: string;
|
|
156
|
+
mimeType: string;
|
|
157
|
+
size: number;
|
|
158
|
+
path: string;
|
|
159
|
+
url: string;
|
|
160
|
+
metadata: Record<string, any>;
|
|
161
|
+
uploadedAt: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Configuration for upload decorators
|
|
166
|
+
*/
|
|
167
|
+
export interface UploadDecoratorConfig extends Partial<UploadConfiguration> {
|
|
168
|
+
/** Field name to apply upload to */
|
|
169
|
+
field?: string;
|
|
170
|
+
|
|
171
|
+
/** Enable batch uploads */
|
|
172
|
+
batch?: boolean;
|
|
173
|
+
|
|
174
|
+
/** Required upload */
|
|
175
|
+
required?: boolean;
|
|
176
|
+
|
|
177
|
+
/** Custom validation message */
|
|
178
|
+
validationMessage?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Upload field types for GraphQL
|
|
183
|
+
*/
|
|
184
|
+
export type UploadGraphQLType = "Upload" | "[Upload]" | "Upload!" | "[Upload]!";
|