@sylphx/flow 1.0.1 → 1.0.3
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/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard error types for the application
|
|
3
|
+
* Typed errors enable better error handling and recovery
|
|
4
|
+
*
|
|
5
|
+
* DESIGN RATIONALE:
|
|
6
|
+
* - Discriminated union for all error types
|
|
7
|
+
* - Each error type has specific context
|
|
8
|
+
* - Enables type-safe error handling
|
|
9
|
+
* - Clear error categories for recovery strategies
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Base error type with common fields
|
|
14
|
+
*/
|
|
15
|
+
export interface BaseError {
|
|
16
|
+
readonly kind: string;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
readonly context?: Record<string, unknown>;
|
|
19
|
+
readonly cause?: Error;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration error - invalid configuration or missing required config
|
|
24
|
+
*/
|
|
25
|
+
export interface ConfigError extends BaseError {
|
|
26
|
+
readonly kind: 'ConfigError';
|
|
27
|
+
readonly configKey?: string;
|
|
28
|
+
readonly configPath?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* File system error - file not found, permission denied, etc.
|
|
33
|
+
*/
|
|
34
|
+
export interface FileSystemError extends BaseError {
|
|
35
|
+
readonly kind: 'FileSystemError';
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly operation: 'read' | 'write' | 'delete' | 'create' | 'stat';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Database error - query failure, connection error, etc.
|
|
42
|
+
*/
|
|
43
|
+
export interface DatabaseError extends BaseError {
|
|
44
|
+
readonly kind: 'DatabaseError';
|
|
45
|
+
readonly operation: string;
|
|
46
|
+
readonly table?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validation error - input validation failure
|
|
51
|
+
*/
|
|
52
|
+
export interface ValidationError extends BaseError {
|
|
53
|
+
readonly kind: 'ValidationError';
|
|
54
|
+
readonly field?: string;
|
|
55
|
+
readonly errors: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Network error - HTTP error, timeout, connection refused, etc.
|
|
60
|
+
*/
|
|
61
|
+
export interface NetworkError extends BaseError {
|
|
62
|
+
readonly kind: 'NetworkError';
|
|
63
|
+
readonly url?: string;
|
|
64
|
+
readonly statusCode?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* CLI error - command line interface specific errors
|
|
69
|
+
*/
|
|
70
|
+
export interface CLIError extends BaseError {
|
|
71
|
+
readonly kind: 'CLIError';
|
|
72
|
+
readonly command?: string;
|
|
73
|
+
readonly exitCode?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Not found error - resource not found
|
|
78
|
+
*/
|
|
79
|
+
export interface NotFoundError extends BaseError {
|
|
80
|
+
readonly kind: 'NotFoundError';
|
|
81
|
+
readonly resourceType: string;
|
|
82
|
+
readonly resourceId: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Permission error - insufficient permissions
|
|
87
|
+
*/
|
|
88
|
+
export interface PermissionError extends BaseError {
|
|
89
|
+
readonly kind: 'PermissionError';
|
|
90
|
+
readonly resource: string;
|
|
91
|
+
readonly requiredPermission: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Unknown error - catch-all for unexpected errors
|
|
96
|
+
*/
|
|
97
|
+
export interface UnknownError extends BaseError {
|
|
98
|
+
readonly kind: 'UnknownError';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Union of all error types
|
|
103
|
+
*/
|
|
104
|
+
export type AppError =
|
|
105
|
+
| ConfigError
|
|
106
|
+
| FileSystemError
|
|
107
|
+
| DatabaseError
|
|
108
|
+
| ValidationError
|
|
109
|
+
| NetworkError
|
|
110
|
+
| CLIError
|
|
111
|
+
| NotFoundError
|
|
112
|
+
| PermissionError
|
|
113
|
+
| UnknownError;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Error constructors
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
export const configError = (
|
|
120
|
+
message: string,
|
|
121
|
+
options?: {
|
|
122
|
+
configKey?: string;
|
|
123
|
+
configPath?: string;
|
|
124
|
+
context?: Record<string, unknown>;
|
|
125
|
+
cause?: Error;
|
|
126
|
+
}
|
|
127
|
+
): ConfigError => ({
|
|
128
|
+
kind: 'ConfigError',
|
|
129
|
+
message,
|
|
130
|
+
configKey: options?.configKey,
|
|
131
|
+
configPath: options?.configPath,
|
|
132
|
+
context: options?.context,
|
|
133
|
+
cause: options?.cause,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export const fileSystemError = (
|
|
137
|
+
message: string,
|
|
138
|
+
path: string,
|
|
139
|
+
operation: 'read' | 'write' | 'delete' | 'create' | 'stat',
|
|
140
|
+
options?: { context?: Record<string, unknown>; cause?: Error }
|
|
141
|
+
): FileSystemError => ({
|
|
142
|
+
kind: 'FileSystemError',
|
|
143
|
+
message,
|
|
144
|
+
path,
|
|
145
|
+
operation,
|
|
146
|
+
context: options?.context,
|
|
147
|
+
cause: options?.cause,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
export const databaseError = (
|
|
151
|
+
message: string,
|
|
152
|
+
operation: string,
|
|
153
|
+
options?: { table?: string; context?: Record<string, unknown>; cause?: Error }
|
|
154
|
+
): DatabaseError => ({
|
|
155
|
+
kind: 'DatabaseError',
|
|
156
|
+
message,
|
|
157
|
+
operation,
|
|
158
|
+
table: options?.table,
|
|
159
|
+
context: options?.context,
|
|
160
|
+
cause: options?.cause,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const validationError = (
|
|
164
|
+
message: string,
|
|
165
|
+
errors: string[],
|
|
166
|
+
options?: { field?: string; context?: Record<string, unknown> }
|
|
167
|
+
): ValidationError => ({
|
|
168
|
+
kind: 'ValidationError',
|
|
169
|
+
message,
|
|
170
|
+
field: options?.field,
|
|
171
|
+
errors,
|
|
172
|
+
context: options?.context,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export const networkError = (
|
|
176
|
+
message: string,
|
|
177
|
+
options?: { url?: string; statusCode?: number; context?: Record<string, unknown>; cause?: Error }
|
|
178
|
+
): NetworkError => ({
|
|
179
|
+
kind: 'NetworkError',
|
|
180
|
+
message,
|
|
181
|
+
url: options?.url,
|
|
182
|
+
statusCode: options?.statusCode,
|
|
183
|
+
context: options?.context,
|
|
184
|
+
cause: options?.cause,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
export const cliError = (
|
|
188
|
+
message: string,
|
|
189
|
+
options?: {
|
|
190
|
+
command?: string;
|
|
191
|
+
exitCode?: number;
|
|
192
|
+
context?: Record<string, unknown>;
|
|
193
|
+
cause?: Error;
|
|
194
|
+
}
|
|
195
|
+
): CLIError => ({
|
|
196
|
+
kind: 'CLIError',
|
|
197
|
+
message,
|
|
198
|
+
command: options?.command,
|
|
199
|
+
exitCode: options?.exitCode,
|
|
200
|
+
context: options?.context,
|
|
201
|
+
cause: options?.cause,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export const notFoundError = (
|
|
205
|
+
message: string,
|
|
206
|
+
resourceType: string,
|
|
207
|
+
resourceId: string,
|
|
208
|
+
options?: { context?: Record<string, unknown>; cause?: Error }
|
|
209
|
+
): NotFoundError => ({
|
|
210
|
+
kind: 'NotFoundError',
|
|
211
|
+
message,
|
|
212
|
+
resourceType,
|
|
213
|
+
resourceId,
|
|
214
|
+
context: options?.context,
|
|
215
|
+
cause: options?.cause,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
export const permissionError = (
|
|
219
|
+
message: string,
|
|
220
|
+
resource: string,
|
|
221
|
+
requiredPermission: string,
|
|
222
|
+
options?: { context?: Record<string, unknown>; cause?: Error }
|
|
223
|
+
): PermissionError => ({
|
|
224
|
+
kind: 'PermissionError',
|
|
225
|
+
message,
|
|
226
|
+
resource,
|
|
227
|
+
requiredPermission,
|
|
228
|
+
context: options?.context,
|
|
229
|
+
cause: options?.cause,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
export const unknownError = (
|
|
233
|
+
message: string,
|
|
234
|
+
options?: { context?: Record<string, unknown>; cause?: Error }
|
|
235
|
+
): UnknownError => ({
|
|
236
|
+
kind: 'UnknownError',
|
|
237
|
+
message,
|
|
238
|
+
context: options?.context,
|
|
239
|
+
cause: options?.cause,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Convert unknown error to AppError
|
|
244
|
+
*/
|
|
245
|
+
export const toAppError = (error: unknown): AppError => {
|
|
246
|
+
if (isAppError(error)) {
|
|
247
|
+
return error;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (error instanceof Error) {
|
|
251
|
+
return unknownError(error.message, { cause: error });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return unknownError(String(error));
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Type guard for AppError
|
|
259
|
+
*/
|
|
260
|
+
export const isAppError = (error: unknown): error is AppError => {
|
|
261
|
+
return typeof error === 'object' && error !== null && 'kind' in error && 'message' in error;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Format error for display
|
|
266
|
+
*/
|
|
267
|
+
export const formatError = (error: AppError): string => {
|
|
268
|
+
let formatted = `[${error.kind}] ${error.message}`;
|
|
269
|
+
|
|
270
|
+
if (error.kind === 'ConfigError' && error.configKey) {
|
|
271
|
+
formatted += `\n Config key: ${error.configKey}`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (error.kind === 'FileSystemError') {
|
|
275
|
+
formatted += `\n Path: ${error.path}`;
|
|
276
|
+
formatted += `\n Operation: ${error.operation}`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (error.kind === 'DatabaseError') {
|
|
280
|
+
formatted += `\n Operation: ${error.operation}`;
|
|
281
|
+
if (error.table) {
|
|
282
|
+
formatted += `\n Table: ${error.table}`;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (error.kind === 'ValidationError') {
|
|
287
|
+
formatted += `\n Errors:`;
|
|
288
|
+
for (const err of error.errors) {
|
|
289
|
+
formatted += `\n - ${err}`;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (error.kind === 'NetworkError') {
|
|
294
|
+
if (error.url) {
|
|
295
|
+
formatted += `\n URL: ${error.url}`;
|
|
296
|
+
}
|
|
297
|
+
if (error.statusCode) {
|
|
298
|
+
formatted += `\n Status: ${error.statusCode}`;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (error.context) {
|
|
303
|
+
formatted += `\n Context: ${JSON.stringify(error.context, null, 2)}`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (error.cause) {
|
|
307
|
+
formatted += `\n Caused by: ${error.cause.message}`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return formatted;
|
|
311
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functional programming utilities
|
|
3
|
+
* Core abstractions for composable, type-safe error handling
|
|
4
|
+
*
|
|
5
|
+
* PRINCIPLES:
|
|
6
|
+
* - Pure functions (no side effects)
|
|
7
|
+
* - Explicit error handling (no exceptions in business logic)
|
|
8
|
+
* - Composable through map/flatMap
|
|
9
|
+
* - Type-safe (leverages TypeScript's type system)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export * from './async.js';
|
|
13
|
+
export * from './either.js';
|
|
14
|
+
export * from './error-handler.js';
|
|
15
|
+
export * from './error-types.js';
|
|
16
|
+
export * from './option.js';
|
|
17
|
+
export * from './pipe.js';
|
|
18
|
+
export * from './result.js';
|
|
19
|
+
export * from './validation.js';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Option type for representing optional values
|
|
3
|
+
* Eliminates null/undefined and makes optionality explicit
|
|
4
|
+
*
|
|
5
|
+
* DESIGN RATIONALE:
|
|
6
|
+
* - Makes absence of value explicit at type level
|
|
7
|
+
* - Eliminates null pointer errors
|
|
8
|
+
* - Composable through map/flatMap
|
|
9
|
+
* - Forces handling of missing values
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type Option<T> = Some<T> | None;
|
|
13
|
+
|
|
14
|
+
export interface Some<T> {
|
|
15
|
+
readonly _tag: 'Some';
|
|
16
|
+
readonly value: T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface None {
|
|
20
|
+
readonly _tag: 'None';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Constructors
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export const some = <T>(value: T): Some<T> => ({
|
|
28
|
+
_tag: 'Some',
|
|
29
|
+
value,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const none: None = {
|
|
33
|
+
_tag: 'None',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create Option from nullable value
|
|
38
|
+
*/
|
|
39
|
+
export const fromNullable = <T>(value: T | null | undefined): Option<T> => {
|
|
40
|
+
if (value === null || value === undefined) {
|
|
41
|
+
return none;
|
|
42
|
+
}
|
|
43
|
+
return some(value);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Type guards
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
export const isSome = <T>(option: Option<T>): option is Some<T> => option._tag === 'Some';
|
|
51
|
+
|
|
52
|
+
export const isNone = <T>(option: Option<T>): option is None => option._tag === 'None';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Transformations
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export const map =
|
|
59
|
+
<T, U>(fn: (value: T) => U) =>
|
|
60
|
+
(option: Option<T>): Option<U> => {
|
|
61
|
+
if (isSome(option)) {
|
|
62
|
+
return some(fn(option.value));
|
|
63
|
+
}
|
|
64
|
+
return none;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const flatMap =
|
|
68
|
+
<T, U>(fn: (value: T) => Option<U>) =>
|
|
69
|
+
(option: Option<T>): Option<U> => {
|
|
70
|
+
if (isSome(option)) {
|
|
71
|
+
return fn(option.value);
|
|
72
|
+
}
|
|
73
|
+
return none;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Extract value or provide default
|
|
78
|
+
*/
|
|
79
|
+
export const getOrElse =
|
|
80
|
+
<T>(defaultValue: T) =>
|
|
81
|
+
(option: Option<T>): T => {
|
|
82
|
+
if (isSome(option)) {
|
|
83
|
+
return option.value;
|
|
84
|
+
}
|
|
85
|
+
return defaultValue;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Extract value or compute default
|
|
90
|
+
*/
|
|
91
|
+
export const getOrElseLazy =
|
|
92
|
+
<T>(fn: () => T) =>
|
|
93
|
+
(option: Option<T>): T => {
|
|
94
|
+
if (isSome(option)) {
|
|
95
|
+
return option.value;
|
|
96
|
+
}
|
|
97
|
+
return fn();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Pattern matching
|
|
102
|
+
*/
|
|
103
|
+
export const match =
|
|
104
|
+
<T, U>(onSome: (value: T) => U, onNone: () => U) =>
|
|
105
|
+
(option: Option<T>): U => {
|
|
106
|
+
if (isSome(option)) {
|
|
107
|
+
return onSome(option.value);
|
|
108
|
+
}
|
|
109
|
+
return onNone();
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Filter based on predicate
|
|
114
|
+
*/
|
|
115
|
+
export const filter =
|
|
116
|
+
<T>(predicate: (value: T) => boolean) =>
|
|
117
|
+
(option: Option<T>): Option<T> => {
|
|
118
|
+
if (isSome(option) && predicate(option.value)) {
|
|
119
|
+
return option;
|
|
120
|
+
}
|
|
121
|
+
return none;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Convert to nullable
|
|
126
|
+
*/
|
|
127
|
+
export const toNullable = <T>(option: Option<T>): T | null => {
|
|
128
|
+
if (isSome(option)) {
|
|
129
|
+
return option.value;
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Convert to undefined
|
|
136
|
+
*/
|
|
137
|
+
export const toUndefined = <T>(option: Option<T>): T | undefined => {
|
|
138
|
+
if (isSome(option)) {
|
|
139
|
+
return option.value;
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function composition utilities
|
|
3
|
+
* Enable declarative data transformation pipelines
|
|
4
|
+
*
|
|
5
|
+
* DESIGN RATIONALE:
|
|
6
|
+
* - Left-to-right composition (more readable than f(g(h(x))))
|
|
7
|
+
* - Type-safe (TypeScript infers types through the pipeline)
|
|
8
|
+
* - Point-free style support
|
|
9
|
+
* - Declarative over imperative
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Compose functions left-to-right
|
|
14
|
+
* pipe(value, fn1, fn2, fn3) === fn3(fn2(fn1(value)))
|
|
15
|
+
*/
|
|
16
|
+
export function pipe<A>(value: A): A;
|
|
17
|
+
export function pipe<A, B>(value: A, fn1: (a: A) => B): B;
|
|
18
|
+
export function pipe<A, B, C>(value: A, fn1: (a: A) => B, fn2: (b: B) => C): C;
|
|
19
|
+
export function pipe<A, B, C, D>(value: A, fn1: (a: A) => B, fn2: (b: B) => C, fn3: (c: C) => D): D;
|
|
20
|
+
export function pipe<A, B, C, D, E>(
|
|
21
|
+
value: A,
|
|
22
|
+
fn1: (a: A) => B,
|
|
23
|
+
fn2: (b: B) => C,
|
|
24
|
+
fn3: (c: C) => D,
|
|
25
|
+
fn4: (d: D) => E
|
|
26
|
+
): E;
|
|
27
|
+
export function pipe<A, B, C, D, E, F>(
|
|
28
|
+
value: A,
|
|
29
|
+
fn1: (a: A) => B,
|
|
30
|
+
fn2: (b: B) => C,
|
|
31
|
+
fn3: (c: C) => D,
|
|
32
|
+
fn4: (d: D) => E,
|
|
33
|
+
fn5: (e: E) => F
|
|
34
|
+
): F;
|
|
35
|
+
export function pipe<A, B, C, D, E, F, G>(
|
|
36
|
+
value: A,
|
|
37
|
+
fn1: (a: A) => B,
|
|
38
|
+
fn2: (b: B) => C,
|
|
39
|
+
fn3: (c: C) => D,
|
|
40
|
+
fn4: (d: D) => E,
|
|
41
|
+
fn5: (e: E) => F,
|
|
42
|
+
fn6: (f: F) => G
|
|
43
|
+
): G;
|
|
44
|
+
export function pipe<A, B, C, D, E, F, G, H>(
|
|
45
|
+
value: A,
|
|
46
|
+
fn1: (a: A) => B,
|
|
47
|
+
fn2: (b: B) => C,
|
|
48
|
+
fn3: (c: C) => D,
|
|
49
|
+
fn4: (d: D) => E,
|
|
50
|
+
fn5: (e: E) => F,
|
|
51
|
+
fn6: (f: F) => G,
|
|
52
|
+
fn7: (g: G) => H
|
|
53
|
+
): H;
|
|
54
|
+
export function pipe<A, B, C, D, E, F, G, H, I>(
|
|
55
|
+
value: A,
|
|
56
|
+
fn1: (a: A) => B,
|
|
57
|
+
fn2: (b: B) => C,
|
|
58
|
+
fn3: (c: C) => D,
|
|
59
|
+
fn4: (d: D) => E,
|
|
60
|
+
fn5: (e: E) => F,
|
|
61
|
+
fn6: (f: F) => G,
|
|
62
|
+
fn7: (g: G) => H,
|
|
63
|
+
fn8: (h: H) => I
|
|
64
|
+
): I;
|
|
65
|
+
export function pipe<A, B, C, D, E, F, G, H, I, J>(
|
|
66
|
+
value: A,
|
|
67
|
+
fn1: (a: A) => B,
|
|
68
|
+
fn2: (b: B) => C,
|
|
69
|
+
fn3: (c: C) => D,
|
|
70
|
+
fn4: (d: D) => E,
|
|
71
|
+
fn5: (e: E) => F,
|
|
72
|
+
fn6: (f: F) => G,
|
|
73
|
+
fn7: (g: G) => H,
|
|
74
|
+
fn8: (h: H) => I,
|
|
75
|
+
fn9: (i: I) => J
|
|
76
|
+
): J;
|
|
77
|
+
export function pipe(value: any, ...fns: Array<(arg: any) => any>): any {
|
|
78
|
+
return fns.reduce((acc, fn) => fn(acc), value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Create a composed function from multiple functions
|
|
83
|
+
* flow(fn1, fn2, fn3) creates a new function that applies fn1, then fn2, then fn3
|
|
84
|
+
*/
|
|
85
|
+
export function flow<A, B>(fn1: (a: A) => B): (a: A) => B;
|
|
86
|
+
export function flow<A, B, C>(fn1: (a: A) => B, fn2: (b: B) => C): (a: A) => C;
|
|
87
|
+
export function flow<A, B, C, D>(fn1: (a: A) => B, fn2: (b: B) => C, fn3: (c: C) => D): (a: A) => D;
|
|
88
|
+
export function flow<A, B, C, D, E>(
|
|
89
|
+
fn1: (a: A) => B,
|
|
90
|
+
fn2: (b: B) => C,
|
|
91
|
+
fn3: (c: C) => D,
|
|
92
|
+
fn4: (d: D) => E
|
|
93
|
+
): (a: A) => E;
|
|
94
|
+
export function flow<A, B, C, D, E, F>(
|
|
95
|
+
fn1: (a: A) => B,
|
|
96
|
+
fn2: (b: B) => C,
|
|
97
|
+
fn3: (c: C) => D,
|
|
98
|
+
fn4: (d: D) => E,
|
|
99
|
+
fn5: (e: E) => F
|
|
100
|
+
): (a: A) => F;
|
|
101
|
+
export function flow<A, B, C, D, E, F, G>(
|
|
102
|
+
fn1: (a: A) => B,
|
|
103
|
+
fn2: (b: B) => C,
|
|
104
|
+
fn3: (c: C) => D,
|
|
105
|
+
fn4: (d: D) => E,
|
|
106
|
+
fn5: (e: E) => F,
|
|
107
|
+
fn6: (f: F) => G
|
|
108
|
+
): (a: A) => G;
|
|
109
|
+
export function flow<A, B, C, D, E, F, G, H>(
|
|
110
|
+
fn1: (a: A) => B,
|
|
111
|
+
fn2: (b: B) => C,
|
|
112
|
+
fn3: (c: C) => D,
|
|
113
|
+
fn4: (d: D) => E,
|
|
114
|
+
fn5: (e: E) => F,
|
|
115
|
+
fn6: (f: F) => G,
|
|
116
|
+
fn7: (g: G) => H
|
|
117
|
+
): (a: A) => H;
|
|
118
|
+
export function flow<A, B, C, D, E, F, G, H, I>(
|
|
119
|
+
fn1: (a: A) => B,
|
|
120
|
+
fn2: (b: B) => C,
|
|
121
|
+
fn3: (c: C) => D,
|
|
122
|
+
fn4: (d: D) => E,
|
|
123
|
+
fn5: (e: E) => F,
|
|
124
|
+
fn6: (f: F) => G,
|
|
125
|
+
fn7: (g: G) => H,
|
|
126
|
+
fn8: (h: H) => I
|
|
127
|
+
): (a: A) => I;
|
|
128
|
+
export function flow<A, B, C, D, E, F, G, H, I, J>(
|
|
129
|
+
fn1: (a: A) => B,
|
|
130
|
+
fn2: (b: B) => C,
|
|
131
|
+
fn3: (c: C) => D,
|
|
132
|
+
fn4: (d: D) => E,
|
|
133
|
+
fn5: (e: E) => F,
|
|
134
|
+
fn6: (f: F) => G,
|
|
135
|
+
fn7: (g: G) => H,
|
|
136
|
+
fn8: (h: H) => I,
|
|
137
|
+
fn9: (i: I) => J
|
|
138
|
+
): (a: A) => J;
|
|
139
|
+
export function flow(...fns: Array<(arg: any) => any>): (arg: any) => any {
|
|
140
|
+
return (value: any) => pipe(value, ...fns);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Identity function - returns input unchanged
|
|
145
|
+
* Useful as a no-op transformation or default
|
|
146
|
+
*/
|
|
147
|
+
export const identity = <T>(value: T): T => value;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Constant function - returns a function that always returns the same value
|
|
151
|
+
* Useful for providing defaults
|
|
152
|
+
*/
|
|
153
|
+
export const constant =
|
|
154
|
+
<T>(value: T) =>
|
|
155
|
+
(): T =>
|
|
156
|
+
value;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Tap - run a side effect and return the original value
|
|
160
|
+
* Useful for debugging or logging in a pipeline
|
|
161
|
+
*/
|
|
162
|
+
export const tap =
|
|
163
|
+
<T>(fn: (value: T) => void) =>
|
|
164
|
+
(value: T): T => {
|
|
165
|
+
fn(value);
|
|
166
|
+
return value;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Memoize - cache function results
|
|
171
|
+
* Only for pure functions with string/number arguments
|
|
172
|
+
*/
|
|
173
|
+
export const memoize = <Args extends Array<string | number>, R>(
|
|
174
|
+
fn: (...args: Args) => R
|
|
175
|
+
): ((...args: Args) => R) => {
|
|
176
|
+
const cache = new Map<string, R>();
|
|
177
|
+
|
|
178
|
+
return (...args: Args): R => {
|
|
179
|
+
const key = JSON.stringify(args);
|
|
180
|
+
|
|
181
|
+
if (cache.has(key)) {
|
|
182
|
+
return cache.get(key)!;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const result = fn(...args);
|
|
186
|
+
cache.set(key, result);
|
|
187
|
+
return result;
|
|
188
|
+
};
|
|
189
|
+
};
|