@uploadista/server 0.0.9 → 0.0.11

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/dist/index.d.cts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { n as getAuthCredentials, t as AuthCredentialsResponse } from "./index-50KlDIjc.cjs";
2
- import { DataStoreCapabilities, Flow, FlowData, FlowJob, FlowServer, UploadEvent, UploadFile, UploadServer, UploadistaError } from "@uploadista/core";
2
+ import * as _uploadista_core0 from "@uploadista/core";
3
+ import { DataStoreCapabilities, Flow, FlowData, FlowJob, FlowServer, PluginLayer, UploadEvent, UploadFile, UploadServer, UploadistaError } from "@uploadista/core";
3
4
  import { Context, Effect, Layer } from "effect";
4
- import { Flow as Flow$1, FlowProvider, FlowServerShape } from "@uploadista/core/flow";
5
+ import { CredentialProviderLayer, ExtractLayerServices, Flow as Flow$1, FlowProvider, FlowServerShape, ImageAiPluginLayer, ImagePluginLayer, ZipPluginLayer } from "@uploadista/core/flow";
6
+ import z$1, { z } from "zod";
5
7
  import { BaseEventEmitterService, BaseKvStoreService, DataStoreConfig, EventBroadcasterService, UploadFileDataStore, UploadFileDataStores, UploadFileKVStore } from "@uploadista/core/types";
6
8
  import { GenerateId } from "@uploadista/core/utils";
7
- import z$1, { z } from "zod";
9
+ import { MetricsService } from "@uploadista/observability";
8
10
  import { UploadServer as UploadServer$1, UploadServerShape } from "@uploadista/core/upload";
9
11
  import { UploadistaError as UploadistaError$1 } from "@uploadista/core/errors";
12
+ import { ExtractLayerServices as ExtractLayerServices$1 } from "@uploadista/core/flow/types";
10
13
 
11
14
  //#region src/core/routes.d.ts
12
15
  type UploadistaRouteType = "create-upload" | "get-capabilities" | "get-upload" | "upload-chunk" | "get-flow" | "run-flow" | "job-status" | "resume-flow" | "pause-flow" | "cancel-flow" | "not-found" | "bad-request" | "method-not-allowed" | "unsupported-content-type";
@@ -418,6 +421,161 @@ declare const AuthCacheServiceLive: (config?: AuthCacheConfig) => Layer.Layer<Au
418
421
  */
419
422
  declare const NoAuthCacheServiceLive: Layer.Layer<AuthCacheService>;
420
423
  //#endregion
424
+ //#region src/core/plugin-types.d.ts
425
+ /**
426
+ * Utility type to extract all services from a tuple of layers.
427
+ * Given [Layer<A>, Layer<B>], extracts A | B.
428
+ *
429
+ * This is a wrapper around the shared ExtractLayerServices utility from @uploadista/core.
430
+ *
431
+ * @deprecated Use ExtractLayerServices from @uploadista/core/flow/types instead.
432
+ * This will be removed in a future version.
433
+ */
434
+ type ExtractServicesFromLayers<T extends readonly Layer.Layer<any, any, any>[]> = ExtractLayerServices<T>;
435
+ /**
436
+ * Known plugin layer types for better type inference.
437
+ * This union helps TypeScript understand which plugins are available.
438
+ */
439
+ type KnownPluginLayer = ImagePluginLayer | ImageAiPluginLayer | CredentialProviderLayer | ZipPluginLayer;
440
+ /**
441
+ * Type-safe plugin tuple that only accepts known plugin layers.
442
+ * This provides autocomplete and validation for plugin arrays.
443
+ */
444
+ type PluginTuple = readonly KnownPluginLayer[];
445
+ /**
446
+ * Extracts the union of all plugin services from a plugin tuple.
447
+ *
448
+ * Uses the shared ExtractLayerServices utility from @uploadista/core for consistency.
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * type Plugins = [ImagePluginLayer, ZipPluginLayer];
453
+ * type Services = PluginServices<Plugins>;
454
+ * // Services = ImagePlugin | ZipPlugin
455
+ * ```
456
+ */
457
+ type PluginServices<TPlugins extends PluginTuple> = ExtractLayerServices<TPlugins>;
458
+ /**
459
+ * Type-safe flow function that declares its plugin requirements.
460
+ *
461
+ * @template TRequirements - Union of plugin services this flow needs
462
+ *
463
+ * @example
464
+ * ```typescript
465
+ * // Flow that requires ImagePlugin
466
+ * const myFlow: TypeSafeFlowFunction<ImagePlugin> = (flowId, clientId) =>
467
+ * Effect.gen(function* () {
468
+ * const imageService = yield* ImagePlugin;
469
+ * // ...
470
+ * });
471
+ * ```
472
+ */
473
+ type TypeSafeFlowFunction<TRequirements$1 = never> = (flowId: string, clientId: string | null) => Effect.Effect<Flow$1<z.ZodSchema<unknown>, z.ZodSchema<unknown>, TRequirements$1>, UploadistaError, TRequirements$1>;
474
+ /**
475
+ * Validates that plugins satisfy flow requirements.
476
+ *
477
+ * This type creates a compile-time error if required plugins are missing.
478
+ * When validation fails, it returns an error object with detailed information
479
+ * including a human-readable message.
480
+ *
481
+ * @template TPlugins - The plugin tuple provided
482
+ * @template TRequirements - The services required by flows
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * // ✅ Valid: ImagePlugin is provided and required
487
+ * type Valid = ValidatePlugins<[ImagePluginLayer], ImagePlugin>;
488
+ * // Result: true
489
+ *
490
+ * // ❌ Error: ImagePlugin required but not provided
491
+ * type Invalid = ValidatePlugins<[], ImagePlugin>;
492
+ * // Result: {
493
+ * // __error: "MISSING_REQUIRED_PLUGINS";
494
+ * // __message: "Missing required plugins: ...";
495
+ * // __required: ImagePlugin;
496
+ * // __provided: never;
497
+ * // __missing: ImagePlugin;
498
+ * // }
499
+ * ```
500
+ */
501
+ type ValidatePlugins<TPlugins extends PluginTuple, TRequirements$1> = TRequirements$1 extends never ? true : TRequirements$1 extends PluginServices<TPlugins> ? true : {
502
+ readonly __error: "MISSING_REQUIRED_PLUGINS";
503
+ readonly __message: "Missing required plugins. Check __missing field for details.";
504
+ readonly __required: TRequirements$1;
505
+ readonly __provided: PluginServices<TPlugins>;
506
+ readonly __missing: Exclude<TRequirements$1, PluginServices<TPlugins>>;
507
+ readonly __hint: "Add the missing plugins to your server configuration's plugins array.";
508
+ };
509
+ /**
510
+ * Type-safe server configuration with compile-time plugin validation.
511
+ *
512
+ * This ensures that all plugins required by flows are actually provided.
513
+ *
514
+ * @template TPlugins - Tuple of plugin layers
515
+ * @template TFlowRequirements - Union of services that flows need
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * // ✅ Compiles: ImagePlugin provided and required
520
+ * const config: TypeSafePluginConfig<
521
+ * [ImagePluginLayer],
522
+ * ImagePlugin
523
+ * > = {
524
+ * plugins: [sharpImagePlugin],
525
+ * flows: (flowId, clientId) => imageFlow
526
+ * };
527
+ *
528
+ * // ❌ Compile error: ImagePlugin required but not provided
529
+ * const bad: TypeSafePluginConfig<
530
+ * [],
531
+ * ImagePlugin
532
+ * > = {
533
+ * plugins: [],
534
+ * flows: (flowId, clientId) => imageFlow
535
+ * };
536
+ * ```
537
+ */
538
+ type TypeSafePluginConfig<TPlugins extends PluginTuple, TFlowRequirements> = ValidatePlugins<TPlugins, TFlowRequirements> extends true ? {
539
+ plugins: TPlugins;
540
+ flows: TypeSafeFlowFunction<TFlowRequirements>;
541
+ } : ValidatePlugins<TPlugins, TFlowRequirements>;
542
+ /**
543
+ * Extracts plugin requirements from a flow function type.
544
+ *
545
+ * This navigates through the flow function signature to extract the requirements
546
+ * from the Flow type it returns, excluding UploadServer (provided by runtime).
547
+ *
548
+ * @template TFlowFn - The flow function type to extract requirements from
549
+ *
550
+ * @example
551
+ * ```typescript
552
+ * const myFlow = (flowId: string, clientId: string | null) =>
553
+ * Effect.succeed(
554
+ * createFlow({ ... }) // Returns Flow<..., ..., ImagePlugin | ZipPlugin>
555
+ * );
556
+ *
557
+ * type Requirements = ExtractFlowPluginRequirements<typeof myFlow>;
558
+ * // Requirements = ImagePlugin | ZipPlugin
559
+ * ```
560
+ */
561
+ type ExtractFlowPluginRequirements<TFlowFn extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = ReturnType<TFlowFn> extends Effect.Effect<infer TFlow, any, any> ? TFlow extends Flow$1<any, any, infer TRequirements> ? Exclude<TRequirements, never> : never : never;
562
+ /**
563
+ * Helper type to infer plugin requirements from a flow function.
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * const myFlow: TypeSafeFlowFunction<ImagePlugin | ZipPlugin> = ...;
568
+ * type Requirements = InferFlowRequirements<typeof myFlow>;
569
+ * // Requirements = ImagePlugin | ZipPlugin
570
+ * ```
571
+ */
572
+ type InferFlowRequirements<T> = T extends TypeSafeFlowFunction<infer R> ? R : never;
573
+ /**
574
+ * Converts PluginLayer types to Layer.Layer<any, never, any> for runtime use.
575
+ * Maintains type safety at compile time while allowing flexible runtime composition.
576
+ */
577
+ type RuntimePluginLayers<T extends PluginTuple> = { [K in keyof T]: T[K] extends Layer.Layer<infer S, infer E, infer R> ? Layer.Layer<S, E, R> : never };
578
+ //#endregion
421
579
  //#region src/core/types.d.ts
422
580
  /**
423
581
  * Function type for retrieving flows based on flow ID and client ID.
@@ -453,6 +611,8 @@ type FlowsFunction = (flowId: string, clientId: string | null) => Effect.Effect<
453
611
  * @template TRequest - Framework-specific request type
454
612
  * @template TResponse - Framework-specific response type
455
613
  * @template TWebSocket - Framework-specific WebSocket type (optional)
614
+ * @template TFlows - Function type for retrieving flows
615
+ * @template TPlugins - Tuple of plugin layers that provide requirements for flows
456
616
  *
457
617
  * @example
458
618
  * ```typescript
@@ -477,7 +637,7 @@ type FlowsFunction = (flowId: string, clientId: string | null) => Effect.Effect<
477
637
  * const server = await createUploadistaServer(config);
478
638
  * ```
479
639
  */
480
- interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
640
+ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown, TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<Flow$1<z.ZodSchema<unknown>, z.ZodSchema<unknown>, any>, UploadistaError, any> = any, TPlugins extends readonly PluginLayer[] = readonly PluginLayer[]> {
481
641
  /**
482
642
  * Function for retrieving flows by ID.
483
643
  *
@@ -490,7 +650,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
490
650
  * flows: (flowId, clientId) => Effect.succeed(myFlows[flowId])
491
651
  * ```
492
652
  */
493
- flows: FlowsFunction;
653
+ flows: TFlows;
494
654
  /**
495
655
  * Data store configuration for file storage.
496
656
  *
@@ -534,7 +694,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
534
694
  * plugins: [imageProcessingPlugin, virusScanPlugin]
535
695
  * ```
536
696
  */
537
- plugins?: readonly Layer.Layer<any, never, never>[];
697
+ plugins?: TPlugins;
538
698
  /**
539
699
  * Optional: Event emitter layer for progress notifications.
540
700
  *
@@ -610,7 +770,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
610
770
  * metricsLayer: prometheusMetrics()
611
771
  * ```
612
772
  */
613
- metricsLayer?: Layer.Layer<any, never, never>;
773
+ metricsLayer?: Layer.Layer<MetricsService, never, never>;
614
774
  /**
615
775
  * Optional: Buffered data store layer for performance optimization.
616
776
  *
@@ -688,29 +848,398 @@ interface UploadistaServer<TRequest, TResponse, TWebSocketHandler = unknown> {
688
848
  dispose: () => Promise<void>;
689
849
  }
690
850
  //#endregion
851
+ //#region src/core/create-type-safe-server.d.ts
852
+ /**
853
+ * Type-safe configuration for Uploadista server with compile-time plugin validation.
854
+ *
855
+ * This configuration extends the base UploadistaServerConfig with stricter typing
856
+ * that validates plugins match flow requirements at compile time.
857
+ *
858
+ * @template TContext - Framework-specific request context type
859
+ * @template TResponse - Framework-specific response type
860
+ * @template TWebSocket - Framework-specific WebSocket handler type
861
+ * @template TPlugins - Tuple of plugin layers provided to the server
862
+ * @template TFlowRequirements - Union of plugin services required by flows
863
+ */
864
+ type TypeSafeServerConfig<TContext, TResponse, TWebSocket, TPlugins extends PluginTuple, TFlowRequirements = PluginServices<TPlugins>> = Omit<UploadistaServerConfig<TContext, TResponse, TWebSocket>, "flows" | "plugins"> & {
865
+ /**
866
+ * Tuple of plugin layers that provide services to flows.
867
+ * The plugins must satisfy all requirements declared by the flows.
868
+ */
869
+ plugins: TPlugins;
870
+ /**
871
+ * Type-safe flow function with explicit requirements.
872
+ * TypeScript validates that all required plugins are provided.
873
+ */
874
+ flows: TypeSafeFlowFunction<TFlowRequirements>;
875
+ /**
876
+ * Compile-time validation that plugins satisfy flow requirements.
877
+ * If this field has type errors, required plugins are missing.
878
+ */
879
+ __validate?: ValidatePlugins<TPlugins, TFlowRequirements>;
880
+ };
881
+ /**
882
+ * @deprecated Use `createUploadistaServer` with optional type utilities instead.
883
+ *
884
+ * This function is deprecated in favor of the unified `createUploadistaServer` API.
885
+ * The new approach separates validation concerns from server creation, making the
886
+ * API simpler while still providing compile-time validation when desired.
887
+ *
888
+ * ## Migration Guide
889
+ *
890
+ * ### Old Approach (Deprecated)
891
+ * ```typescript
892
+ * import { createTypeSafeServer } from "@uploadista/server";
893
+ *
894
+ * const server = await createTypeSafeServer({
895
+ * plugins: [sharpImagePlugin] as const,
896
+ * flows: myFlowFunction,
897
+ * // ...
898
+ * });
899
+ * ```
900
+ *
901
+ * ### New Approach (Recommended)
902
+ *
903
+ * **Option 1: Runtime validation only (simplest)**
904
+ * ```typescript
905
+ * import { createUploadistaServer } from "@uploadista/server";
906
+ *
907
+ * const server = await createUploadistaServer({
908
+ * plugins: [sharpImagePlugin, zipPlugin],
909
+ * flows: myFlowFunction,
910
+ * // ... Effect validates at runtime
911
+ * });
912
+ * ```
913
+ *
914
+ * **Option 2: With compile-time validation (optional)**
915
+ * ```typescript
916
+ * import {
917
+ * createUploadistaServer,
918
+ * ValidatePlugins,
919
+ * ExtractFlowPluginRequirements
920
+ * } from "@uploadista/server";
921
+ *
922
+ * type Requirements = ExtractFlowPluginRequirements<typeof myFlowFunction>;
923
+ * const plugins = [sharpImagePlugin, zipPlugin] as const;
924
+ * type Validation = ValidatePlugins<typeof plugins, Requirements>;
925
+ * // IDE shows error if plugins don't match requirements
926
+ *
927
+ * const server = await createUploadistaServer({
928
+ * plugins,
929
+ * flows: myFlowFunction,
930
+ * // ...
931
+ * });
932
+ * ```
933
+ *
934
+ * ## Why This Changed
935
+ *
936
+ * 1. **Simpler API**: One function instead of two reduces confusion
937
+ * 2. **Separation of Concerns**: Validation is now optional and separate
938
+ * 3. **Better Flexibility**: Choose validation approach per use case
939
+ * 4. **Clearer Intent**: Explicit validation via type utilities
940
+ * 5. **Same Safety**: Effect-TS still validates at runtime
941
+ *
942
+ * The new approach trusts Effect-TS's design for dynamic dependency injection
943
+ * while providing optional compile-time validation through type utilities.
944
+ *
945
+ * @see createUploadistaServer - The unified server creation API
946
+ * @see ValidatePlugins - Compile-time validation type utility
947
+ * @see ExtractFlowPluginRequirements - Extract requirements from flows
948
+ * @see API_DECISION_GUIDE.md - Complete migration and usage guide
949
+ *
950
+ * @template TContext - Framework-specific request context type
951
+ * @template TResponse - Framework-specific response type
952
+ * @template TWebSocket - Framework-specific WebSocket handler type
953
+ * @template TPlugins - Tuple of plugin layers
954
+ * @template TFlowRequirements - Union of services required by flows
955
+ *
956
+ * @param config - Type-safe server configuration
957
+ * @returns Promise resolving to UploadistaServer instance
958
+ */
959
+ declare function createTypeSafeServer<TContext, TResponse, TWebSocket = unknown, TPlugins extends PluginTuple = PluginTuple, TFlowRequirements = PluginServices<TPlugins>>(config: TypeSafeServerConfig<TContext, TResponse, TWebSocket, TPlugins, TFlowRequirements> & (ValidatePlugins<TPlugins, TFlowRequirements> extends true ? object : ValidatePlugins<TPlugins, TFlowRequirements>)): Promise<UploadistaServer<TContext, TResponse, TWebSocket>>;
960
+ /**
961
+ * Helper function to define flow functions with explicit type requirements.
962
+ * Provides better type inference and autocomplete for plugin services.
963
+ *
964
+ * @template TRequirements - Union of plugin services this flow needs
965
+ *
966
+ * @param fn - The flow function implementation
967
+ * @returns The same function with explicit type annotation
968
+ *
969
+ * @example
970
+ * ```typescript
971
+ * import { ImagePlugin } from "@uploadista/core/flow";
972
+ * import { defineFlow } from "@uploadista/server";
973
+ *
974
+ * // Explicitly declare that this flow requires ImagePlugin
975
+ * const imageProcessingFlow = defineFlow<ImagePlugin>((flowId, clientId) =>
976
+ * Effect.gen(function* () {
977
+ * const imageService = yield* ImagePlugin; // Autocomplete works!
978
+ * const optimized = yield* imageService.optimize(data, { quality: 80 });
979
+ * return createFlow({ ... });
980
+ * })
981
+ * );
982
+ * ```
983
+ */
984
+ declare function defineFlow<TRequirements$1 = never>(fn: TypeSafeFlowFunction<TRequirements$1>): TypeSafeFlowFunction<TRequirements$1>;
985
+ /**
986
+ * Helper to create a flow that requires no plugins.
987
+ * Useful for simple flows that only use built-in functionality.
988
+ *
989
+ * @example
990
+ * ```typescript
991
+ * import { defineSimpleFlow } from "@uploadista/server";
992
+ *
993
+ * const simpleFlow = defineSimpleFlow((flowId, clientId) =>
994
+ * Effect.succeed(createFlow({
995
+ * id: "simple",
996
+ * nodes: [],
997
+ * edges: [],
998
+ * inputSchema: myInputSchema,
999
+ * outputSchema: myOutputSchema
1000
+ * }))
1001
+ * );
1002
+ * ```
1003
+ */
1004
+ declare function defineSimpleFlow(fn: TypeSafeFlowFunction<never>): TypeSafeFlowFunction<never>;
1005
+ //#endregion
1006
+ //#region src/core/plugin-validation.d.ts
1007
+ /**
1008
+ * Result of plugin validation.
1009
+ */
1010
+ type PluginValidationResult = {
1011
+ success: true;
1012
+ } | {
1013
+ success: false;
1014
+ required: string[];
1015
+ provided: string[];
1016
+ missing: string[];
1017
+ suggestions: Array<{
1018
+ name: string;
1019
+ packageName: string;
1020
+ importStatement: string;
1021
+ }>;
1022
+ };
1023
+ /**
1024
+ * Extracts service identifiers from an array of plugin layers.
1025
+ *
1026
+ * @param plugins - Array of plugin layers
1027
+ * @returns Array of service identifier strings
1028
+ */
1029
+ declare function extractServiceIdentifiers(plugins: readonly PluginLayer[]): string[];
1030
+ /**
1031
+ * Validates that all required plugins are provided.
1032
+ *
1033
+ * This is a runtime validation function that checks if the plugins array
1034
+ * contains all services required by the flows. It's called during server
1035
+ * initialization to provide early, clear error messages.
1036
+ *
1037
+ * Note: This validation is best-effort because we can't reliably extract
1038
+ * requirements from flow functions at runtime without executing them.
1039
+ * The main validation happens via Effect-TS's dependency injection.
1040
+ *
1041
+ * @param config - Validation configuration
1042
+ * @returns Validation result with detailed error information if validation fails
1043
+ *
1044
+ * @example
1045
+ * ```typescript
1046
+ * const result = validatePluginRequirements({
1047
+ * plugins: [sharpImagePlugin, zipPlugin],
1048
+ * expectedServices: ['ImagePlugin', 'ZipPlugin']
1049
+ * });
1050
+ *
1051
+ * if (!result.success) {
1052
+ * console.error('Missing plugins:', result.missing);
1053
+ * console.error('Suggestions:', result.suggestions);
1054
+ * }
1055
+ * ```
1056
+ */
1057
+ declare function validatePluginRequirements(config: {
1058
+ plugins: readonly PluginLayer[];
1059
+ expectedServices?: string[];
1060
+ }): PluginValidationResult;
1061
+ /**
1062
+ * Creates a formatted error message for plugin validation failures.
1063
+ *
1064
+ * This generates a detailed, human-readable error message that includes:
1065
+ * - List of required plugins
1066
+ * - List of provided plugins
1067
+ * - List of missing plugins
1068
+ * - Import statements for missing plugins (if known)
1069
+ * - Example server configuration
1070
+ *
1071
+ * @param result - Failed validation result
1072
+ * @returns Formatted error message string
1073
+ *
1074
+ * @example
1075
+ * ```typescript
1076
+ * const result = validatePluginRequirements({ ... });
1077
+ * if (!result.success) {
1078
+ * const message = formatPluginValidationError(result);
1079
+ * throw new Error(message);
1080
+ * }
1081
+ * ```
1082
+ */
1083
+ declare function formatPluginValidationError(result: Extract<PluginValidationResult, {
1084
+ success: false;
1085
+ }>): string;
1086
+ /**
1087
+ * Effect-based plugin validation that can be composed with other Effects.
1088
+ *
1089
+ * This provides an Effect-TS native way to validate plugins, allowing it
1090
+ * to be composed with other Effects in the server initialization pipeline.
1091
+ *
1092
+ * @param config - Validation configuration
1093
+ * @returns Effect that succeeds if validation passes, fails with UploadistaError if not
1094
+ *
1095
+ * @example
1096
+ * ```typescript
1097
+ * const validatedServer = Effect.gen(function* () {
1098
+ * yield* validatePluginRequirementsEffect({
1099
+ * plugins: [sharpImagePlugin],
1100
+ * expectedServices: ['ImagePlugin', 'ZipPlugin']
1101
+ * });
1102
+ *
1103
+ * return yield* createServerEffect(...);
1104
+ * });
1105
+ * ```
1106
+ */
1107
+ declare function validatePluginRequirementsEffect(config: {
1108
+ plugins: readonly PluginLayer[];
1109
+ expectedServices?: string[];
1110
+ }): Effect.Effect<void, Error>;
1111
+ /**
1112
+ * Validates plugin configuration at runtime during server initialization.
1113
+ *
1114
+ * This is a convenience function that performs validation and throws a
1115
+ * descriptive error if validation fails. Use this at the beginning of
1116
+ * createUploadistaServer to fail fast with clear error messages.
1117
+ *
1118
+ * @param config - Validation configuration
1119
+ * @throws Error with detailed message if validation fails
1120
+ *
1121
+ * @example
1122
+ * ```typescript
1123
+ * export const createUploadistaServer = async (config) => {
1124
+ * // Validate plugins early
1125
+ * validatePluginsOrThrow({
1126
+ * plugins: config.plugins,
1127
+ * expectedServices: ['ImagePlugin', 'ZipPlugin']
1128
+ * });
1129
+ *
1130
+ * // Continue with server creation...
1131
+ * };
1132
+ * ```
1133
+ */
1134
+ declare function validatePluginsOrThrow(config: {
1135
+ plugins: readonly PluginLayer[];
1136
+ expectedServices?: string[];
1137
+ }): void;
1138
+ //#endregion
691
1139
  //#region src/core/server.d.ts
692
1140
  /**
693
1141
  * Creates the unified Uploadista server with framework-specific adapter.
694
1142
  *
695
- * This function composes all layers (upload server, flow server, auth, metrics)
696
- * and returns a handler that works with any framework via the provided adapter.
1143
+ * This is the single, unified API for creating an Uploadista server. It handles
1144
+ * all server initialization, layer composition, and runtime setup.
1145
+ *
1146
+ * ## Core Responsibilities
697
1147
  *
698
- * The core server handles:
1148
+ * The server handles:
1149
+ * - Layer composition (upload/flow servers, auth cache, metrics, plugins)
699
1150
  * - Route parsing and matching
700
1151
  * - Auth middleware execution with timeout protection
701
- * - Layer composition (upload/flow servers, auth cache, metrics)
702
1152
  * - Error handling and response formatting
703
1153
  * - Effect program execution with optional tracing
1154
+ * - Plugin validation and dependency injection
1155
+ *
1156
+ * ## Plugin Validation
1157
+ *
1158
+ * The server supports two validation approaches:
1159
+ *
1160
+ * ### 1. Runtime Validation (Recommended for Most Cases)
1161
+ *
1162
+ * The server relies on Effect-TS's dependency injection to validate plugins
1163
+ * at runtime. If a required plugin is missing, Effect will fail with a clear
1164
+ * MissingService error.
1165
+ *
1166
+ * ```typescript
1167
+ * const server = await createUploadistaServer({
1168
+ * flows: getFlowById,
1169
+ * plugins: [sharpImagePlugin, zipPlugin],
1170
+ * dataStore: s3DataStore,
1171
+ * kvStore: redisKvStore,
1172
+ * adapter: honoAdapter({ ... })
1173
+ * });
1174
+ * // If plugins don't match flow requirements, Effect fails with clear error
1175
+ * ```
1176
+ *
1177
+ * ### 2. Compile-Time Validation (Optional)
1178
+ *
1179
+ * For IDE feedback during development, use the ValidatePlugins type utility:
1180
+ *
1181
+ * ```typescript
1182
+ * import {
1183
+ * createUploadistaServer,
1184
+ * ValidatePlugins,
1185
+ * ExtractFlowPluginRequirements
1186
+ * } from '@uploadista/server';
1187
+ *
1188
+ * // Extract requirements from flows
1189
+ * type Requirements = ExtractFlowPluginRequirements<typeof getFlowById>;
1190
+ *
1191
+ * // Define plugins
1192
+ * const plugins = [sharpImagePlugin, zipPlugin] as const;
1193
+ *
1194
+ * // Validate at compile time (optional, for IDE feedback)
1195
+ * type Validation = ValidatePlugins<typeof plugins, Requirements>;
1196
+ * // IDE shows error if plugins don't match requirements
1197
+ *
1198
+ * const server = await createUploadistaServer({
1199
+ * flows: getFlowById,
1200
+ * plugins,
1201
+ * // ...
1202
+ * });
1203
+ * ```
1204
+ *
1205
+ * ### 3. Early Runtime Validation (Optional)
1206
+ *
1207
+ * For better error messages before server starts:
1208
+ *
1209
+ * ```typescript
1210
+ * import { validatePluginsOrThrow } from '@uploadista/server/core';
1211
+ *
1212
+ * validatePluginsOrThrow({
1213
+ * plugins: [sharpImagePlugin],
1214
+ * expectedServices: ['ImagePlugin', 'ZipPlugin']
1215
+ * });
1216
+ * // Throws with helpful error message including import suggestions
1217
+ * ```
1218
+ *
1219
+ * ## Type Safety
1220
+ *
1221
+ * - Plugin requirements are inferred from flow definitions
1222
+ * - Effect-TS ensures dependencies are satisfied at runtime
1223
+ * - Type casting is intentional (see inline docs for rationale)
1224
+ * - Optional compile-time validation available via type utilities
1225
+ *
1226
+ * @template TContext - Framework-specific context type
1227
+ * @template TResponse - Framework-specific response type
1228
+ * @template TWebSocketHandler - WebSocket handler type (if supported)
1229
+ * @template TFlows - Flow function type with plugin requirements
1230
+ * @template TPlugins - Tuple of plugin layers provided
704
1231
  *
705
1232
  * @param config - Server configuration including adapter and business logic
706
- * @returns Object with handler function, optional WebSocket handler, and base URL
1233
+ * @returns Promise resolving to server instance with handler and metadata
707
1234
  *
708
- * @example
1235
+ * @example Basic Usage
709
1236
  * ```typescript
710
1237
  * import { createUploadistaServer, honoAdapter } from "@uploadista/server";
1238
+ * import { sharpImagePlugin } from "@uploadista/flow-images-sharp";
711
1239
  *
712
1240
  * const server = await createUploadistaServer({
713
1241
  * flows: getFlowById,
1242
+ * plugins: [sharpImagePlugin],
714
1243
  * dataStore: { type: "s3", config: { bucket: "uploads" } },
715
1244
  * kvStore: redisKvStore,
716
1245
  * adapter: honoAdapter({
@@ -721,8 +1250,32 @@ interface UploadistaServer<TRequest, TResponse, TWebSocketHandler = unknown> {
721
1250
  * // Use with Hono
722
1251
  * app.all("/uploadista/*", server.handler);
723
1252
  * ```
1253
+ *
1254
+ * @example With Compile-Time Validation
1255
+ * ```typescript
1256
+ * import {
1257
+ * createUploadistaServer,
1258
+ * ValidatePlugins,
1259
+ * ExtractFlowPluginRequirements
1260
+ * } from "@uploadista/server";
1261
+ *
1262
+ * type Requirements = ExtractFlowPluginRequirements<typeof getFlowById>;
1263
+ * const plugins = [sharpImagePlugin, zipPlugin] as const;
1264
+ * type Validation = ValidatePlugins<typeof plugins, Requirements>;
1265
+ *
1266
+ * const server = await createUploadistaServer({
1267
+ * flows: getFlowById,
1268
+ * plugins,
1269
+ * // ... rest of config
1270
+ * });
1271
+ * ```
1272
+ *
1273
+ * @see ValidatePlugins - Compile-time plugin validation
1274
+ * @see ExtractFlowPluginRequirements - Extract requirements from flows
1275
+ * @see validatePluginRequirements - Runtime validation helper
1276
+ * @see API_DECISION_GUIDE.md - Complete guide for choosing validation approach
724
1277
  */
725
- declare const createUploadistaServer: <TContext, TResponse, TWebSocketHandler = unknown>({
1278
+ declare const createUploadistaServer: <TContext, TResponse, TWebSocketHandler = unknown, TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<Flow$1<z.ZodSchema<unknown>, z.ZodSchema<unknown>, any>, UploadistaError, any> = any, TPlugins extends readonly PluginLayer[] = readonly PluginLayer[]>({
726
1279
  flows,
727
1280
  dataStore,
728
1281
  kvStore,
@@ -736,7 +1289,7 @@ declare const createUploadistaServer: <TContext, TResponse, TWebSocketHandler =
736
1289
  bufferedDataStore,
737
1290
  adapter,
738
1291
  authCacheConfig
739
- }: UploadistaServerConfig<TContext, TResponse, TWebSocketHandler>) => Promise<UploadistaServer<TContext, TResponse, TWebSocketHandler>>;
1292
+ }: UploadistaServerConfig<TContext, TResponse, TWebSocketHandler, TFlows, TPlugins>) => Promise<UploadistaServer<TContext, TResponse, TWebSocketHandler>>;
740
1293
  //#endregion
741
1294
  //#region src/core/websocket-routes.d.ts
742
1295
  /**
@@ -839,7 +1392,7 @@ type WebSocketConnectionRequest = {
839
1392
  * Handles WebSocket connection opening
840
1393
  * Subscribes to the appropriate events based on the connection request
841
1394
  */
842
- declare const handleWebSocketOpen: (request: WebSocketConnectionRequest, uploadServer: UploadServerShape, flowServer: FlowServerShape) => Effect.Effect<void, never, unknown>;
1395
+ declare const handleWebSocketOpen: (request: WebSocketConnectionRequest, uploadServer: UploadServerShape, flowServer: FlowServerShape) => Effect.Effect<void, never, never>;
843
1396
  /**
844
1397
  * Handles incoming WebSocket messages
845
1398
  * Currently supports ping/pong for connection keep-alive
@@ -849,7 +1402,7 @@ declare const handleWebSocketMessage: (message: string, connection: WebSocketCon
849
1402
  * Handles WebSocket connection closing
850
1403
  * Unsubscribes from all events and cleans up resources
851
1404
  */
852
- declare const handleWebSocketClose: (request: WebSocketConnectionRequest, uploadServer: UploadServerShape, flowServer: FlowServerShape) => Effect.Effect<void, never, unknown>;
1405
+ declare const handleWebSocketClose: (request: WebSocketConnectionRequest, uploadServer: UploadServerShape, flowServer: FlowServerShape) => Effect.Effect<void, never, never>;
853
1406
  /**
854
1407
  * Handles WebSocket errors
855
1408
  */
@@ -1233,7 +1786,7 @@ declare const createUploadServerLayer: ({
1233
1786
  dataStore,
1234
1787
  bufferedDataStore,
1235
1788
  generateId
1236
- }: UploadServerLayerConfig) => Layer.Layer<unknown, unknown, any>;
1789
+ }: UploadServerLayerConfig) => Layer.Layer<UploadServer$1, never, never>;
1237
1790
  /**
1238
1791
  * Creates the flow server layer with all dependencies composed.
1239
1792
  * This layer handles file processing workflows with multi-stage pipelines.
@@ -1268,13 +1821,83 @@ declare const createFlowServerLayer: ({
1268
1821
  eventEmitter,
1269
1822
  flowProvider,
1270
1823
  uploadServer
1271
- }: FlowServerLayerConfig) => Layer.Layer<unknown, unknown, any>;
1824
+ }: FlowServerLayerConfig) => Layer.Layer<_uploadista_core0.FlowServer, never, never>;
1272
1825
  //#endregion
1273
1826
  //#region src/plugins-typing.d.ts
1274
- type LayerSuccessUnion<Layers extends readonly Layer.Layer<any, never, never>[]> = Layers[number] extends Layer.Layer<infer Success, never, never> ? Success : never;
1827
+ /**
1828
+ * @deprecated Use `ExtractLayerServices` from `@uploadista/core/flow/types` instead.
1829
+ *
1830
+ * Extracts service types from a tuple of layers.
1831
+ *
1832
+ * @example Migration
1833
+ * ```typescript
1834
+ * // Old
1835
+ * import { LayerSuccessUnion } from '@uploadista/server/plugins-typing';
1836
+ * type Services = LayerSuccessUnion<[ImagePluginLayer, ZipPluginLayer]>;
1837
+ *
1838
+ * // New
1839
+ * import { ExtractLayerServices } from '@uploadista/core/flow/types';
1840
+ * type Services = ExtractLayerServices<[ImagePluginLayer, ZipPluginLayer]>;
1841
+ * ```
1842
+ */
1843
+ type LayerSuccessUnion<Layers extends readonly Layer.Layer<any, never, never>[]> = ExtractLayerServices$1<Layers>;
1844
+ /**
1845
+ * @deprecated This type is deprecated. Extract flow requirements directly from your flow types instead.
1846
+ *
1847
+ * Extracts the success type from a flow function's Effect return value.
1848
+ */
1275
1849
  type FlowSuccess<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = ReturnType<TFlows> extends Effect.Effect<infer Success, unknown, unknown> ? Success : never;
1850
+ /**
1851
+ * @deprecated Use `ExtractFlowPluginRequirements` from `@uploadista/server/core/plugin-types` instead.
1852
+ *
1853
+ * Extracts plugin requirements from a flow function, excluding UploadServer.
1854
+ *
1855
+ * @example Migration
1856
+ * ```typescript
1857
+ * // Old
1858
+ * import { FlowRequirementsOf } from '@uploadista/server/plugins-typing';
1859
+ * type Requirements = FlowRequirementsOf<typeof myFlowFunction>;
1860
+ *
1861
+ * // New
1862
+ * import { ExtractFlowPluginRequirements } from '@uploadista/server/core/plugin-types';
1863
+ * type Requirements = ExtractFlowPluginRequirements<typeof myFlowFunction>;
1864
+ * ```
1865
+ */
1276
1866
  type FlowRequirementsOf<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = FlowSuccess<TFlows> extends Flow<z$1.ZodSchema<unknown>, z$1.ZodSchema<unknown>, infer R> ? Exclude<R, UploadServer> : never;
1867
+ /**
1868
+ * @deprecated Use `ExtractFlowPluginRequirements` from `@uploadista/server/core/plugin-types` instead.
1869
+ *
1870
+ * This is an alias for FlowRequirementsOf and provides the same functionality.
1871
+ *
1872
+ * @example Migration
1873
+ * ```typescript
1874
+ * // Old
1875
+ * import { RequiredPluginsOf } from '@uploadista/server/plugins-typing';
1876
+ * type Requirements = RequiredPluginsOf<typeof myFlowFunction>;
1877
+ *
1878
+ * // New
1879
+ * import { ExtractFlowPluginRequirements } from '@uploadista/server/core/plugin-types';
1880
+ * type Requirements = ExtractFlowPluginRequirements<typeof myFlowFunction>;
1881
+ * ```
1882
+ */
1277
1883
  type RequiredPluginsOf<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = Exclude<FlowRequirementsOf<TFlows>, UploadServer>;
1884
+ /**
1885
+ * @deprecated Use `ValidatePlugins` from `@uploadista/server/core/plugin-types` instead.
1886
+ *
1887
+ * This type validates plugin requirements at compile time.
1888
+ *
1889
+ * @example Migration
1890
+ * ```typescript
1891
+ * // Old
1892
+ * import { PluginAssertion } from '@uploadista/server/plugins-typing';
1893
+ * type Validation = PluginAssertion<typeof myFlowFunction, typeof plugins>;
1894
+ *
1895
+ * // New
1896
+ * import { ValidatePlugins, ExtractFlowPluginRequirements } from '@uploadista/server/core/plugin-types';
1897
+ * type Requirements = ExtractFlowPluginRequirements<typeof myFlowFunction>;
1898
+ * type Validation = ValidatePlugins<typeof plugins, Requirements>;
1899
+ * ```
1900
+ */
1278
1901
  type PluginAssertion<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>, TPlugins extends readonly Layer.Layer<any, never, never>[]> = Exclude<RequiredPluginsOf<TFlows>, LayerSuccessUnion<TPlugins>> extends never ? unknown : {
1279
1902
  __missingPlugins: Exclude<RequiredPluginsOf<TFlows>, LayerSuccessUnion<TPlugins>>;
1280
1903
  };
@@ -1339,5 +1962,5 @@ declare const AuthContextServiceLive: (authContext: AuthContext | null) => Layer
1339
1962
  */
1340
1963
  declare const NoAuthContextServiceLive: Layer.Layer<AuthContextService>;
1341
1964
  //#endregion
1342
- export { AdapterError, AuthCacheConfig, AuthCacheService, AuthCacheServiceLive, AuthContext, AuthContextService, AuthContextServiceLive, AuthCredentialsResponse, AuthFailedEvent, AuthResult, BadRequestError, BadRequestRequest, BadRequestResponse, CancelFlowRequest, CancelFlowResponse, ConnectionEvent, CreateUploadRequest, CreateUploadResponse, ErrorEvent, FlowEventMessage, FlowRequirementsOf, FlowServerLayerConfig, FlowSuccess, FlowsFunction, GetCapabilitiesRequest, GetCapabilitiesResponse, GetFlowRequest, GetFlowResponse, GetJobStatusRequest, GetJobStatusResponse, GetUploadRequest, GetUploadResponse, InvalidPathEvent, LayerSuccessUnion, MethodNotAllowedRequest, MethodNotAllowedResponse, NoAuthCacheServiceLive, NoAuthContextServiceLive, NotFoundError, NotFoundRequest, NotFoundResponse, PauseFlowRequest, PauseFlowResponse, PingEvent, PluginAssertion, RequiredPluginsOf, ResumeFlowRequest, ResumeFlowResponse, RunFlowRequest, RunFlowResponse, ServerAdapter, StandardRequest, StandardResponse, SubscribeFlowEvent, SubscribeUploadEvent, UnsubscribeFlowEvent, UnsubscribeUploadEvent, UnsupportedContentTypeRequest, UnsupportedContentTypeResponse, UploadChunkRequest, UploadChunkResponse, UploadEventMessage, UploadServerLayerConfig, UploadistaRequest, UploadistaResponse, UploadistaRoute, UploadistaRouteType, UploadistaServer, UploadistaServerConfig, UploadistaStandardResponse, ValidationError, type WebSocketConnection, type WebSocketConnectionRequest, WebSocketEvent, WebSocketEventType, WebSocketHandler, WebSocketIncomingEvent, WebSocketOutgoingEvent, createErrorResponseBody, createFlowServerLayer, createGenericErrorResponseBody, createUploadServerLayer, createUploadistaErrorResponseBody, createUploadistaServer, extractFlowAndStorageId, extractJobAndNodeId, extractJobIdFromStatus, getAuthCredentials, getLastSegment, getRouteSegments, handleFlowError, handleWebSocketClose, handleWebSocketError, handleWebSocketMessage, handleWebSocketOpen, hasBasePath, parseUrlSegments };
1965
+ export { AdapterError, AuthCacheConfig, AuthCacheService, AuthCacheServiceLive, AuthContext, AuthContextService, AuthContextServiceLive, AuthCredentialsResponse, AuthFailedEvent, AuthResult, BadRequestError, BadRequestRequest, BadRequestResponse, CancelFlowRequest, CancelFlowResponse, ConnectionEvent, CreateUploadRequest, CreateUploadResponse, ErrorEvent, ExtractFlowPluginRequirements, ExtractServicesFromLayers, FlowEventMessage, FlowRequirementsOf, FlowServerLayerConfig, FlowSuccess, FlowsFunction, GetCapabilitiesRequest, GetCapabilitiesResponse, GetFlowRequest, GetFlowResponse, GetJobStatusRequest, GetJobStatusResponse, GetUploadRequest, GetUploadResponse, InferFlowRequirements, InvalidPathEvent, KnownPluginLayer, LayerSuccessUnion, MethodNotAllowedRequest, MethodNotAllowedResponse, NoAuthCacheServiceLive, NoAuthContextServiceLive, NotFoundError, NotFoundRequest, NotFoundResponse, PauseFlowRequest, PauseFlowResponse, PingEvent, PluginAssertion, PluginServices, PluginTuple, PluginValidationResult, RequiredPluginsOf, ResumeFlowRequest, ResumeFlowResponse, RunFlowRequest, RunFlowResponse, RuntimePluginLayers, ServerAdapter, StandardRequest, StandardResponse, SubscribeFlowEvent, SubscribeUploadEvent, TypeSafeFlowFunction, TypeSafePluginConfig, TypeSafeServerConfig, UnsubscribeFlowEvent, UnsubscribeUploadEvent, UnsupportedContentTypeRequest, UnsupportedContentTypeResponse, UploadChunkRequest, UploadChunkResponse, UploadEventMessage, UploadServerLayerConfig, UploadistaRequest, UploadistaResponse, UploadistaRoute, UploadistaRouteType, UploadistaServer, UploadistaServerConfig, UploadistaStandardResponse, ValidatePlugins, ValidationError, type WebSocketConnection, type WebSocketConnectionRequest, WebSocketEvent, WebSocketEventType, WebSocketHandler, WebSocketIncomingEvent, WebSocketOutgoingEvent, createErrorResponseBody, createFlowServerLayer, createGenericErrorResponseBody, createTypeSafeServer, createUploadServerLayer, createUploadistaErrorResponseBody, createUploadistaServer, defineFlow, defineSimpleFlow, extractFlowAndStorageId, extractJobAndNodeId, extractJobIdFromStatus, extractServiceIdentifiers, formatPluginValidationError, getAuthCredentials, getLastSegment, getRouteSegments, handleFlowError, handleWebSocketClose, handleWebSocketError, handleWebSocketMessage, handleWebSocketOpen, hasBasePath, parseUrlSegments, validatePluginRequirements, validatePluginRequirementsEffect, validatePluginsOrThrow };
1343
1966
  //# sourceMappingURL=index.d.cts.map