@uploadista/server 0.0.10 → 0.0.12

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.mts CHANGED
@@ -1,13 +1,15 @@
1
1
  import { n as getAuthCredentials, t as AuthCredentialsResponse } from "./index--Lny6VJP.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
- import { Flow, FlowProvider, FlowServerShape } from "@uploadista/core/flow";
3
+ import { CredentialProviderLayer, ExtractLayerServices, Flow, FlowProvider, FlowServerShape, ImageAiPluginLayer, ImagePluginLayer, ZipPluginLayer } from "@uploadista/core/flow";
4
4
  import { BaseEventEmitterService, BaseKvStoreService, DataStoreConfig, EventBroadcasterService, UploadFileDataStore, UploadFileDataStores, UploadFileKVStore } from "@uploadista/core/types";
5
5
  import { GenerateId } from "@uploadista/core/utils";
6
+ import { MetricsService } from "@uploadista/observability";
6
7
  import { UploadServer, UploadServerShape } from "@uploadista/core/upload";
7
8
  import { UploadistaError } from "@uploadista/core/errors";
8
9
  import * as _uploadista_core0 from "@uploadista/core";
9
- import { DataStoreCapabilities, Flow as Flow$1, FlowData, FlowJob, FlowServer as FlowServer$1, UploadEvent, UploadFile, UploadServer as UploadServer$1, UploadistaError as UploadistaError$1 } from "@uploadista/core";
10
+ import { DataStoreCapabilities, Flow as Flow$1, FlowData, FlowJob, FlowServer as FlowServer$1, PluginLayer, UploadEvent, UploadFile, UploadServer as UploadServer$1, UploadistaError as UploadistaError$1 } from "@uploadista/core";
10
11
  import z$1, { z } from "zod";
12
+ import { ExtractLayerServices as ExtractLayerServices$1 } from "@uploadista/core/flow/types";
11
13
 
12
14
  //#region src/core/routes.d.ts
13
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";
@@ -419,6 +421,161 @@ declare const AuthCacheServiceLive: (config?: AuthCacheConfig) => Layer.Layer<Au
419
421
  */
420
422
  declare const NoAuthCacheServiceLive: Layer.Layer<AuthCacheService>;
421
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<z.ZodSchema<unknown>, z.ZodSchema<unknown>, TRequirements$1>, UploadistaError$1, 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<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
422
579
  //#region src/core/types.d.ts
423
580
  /**
424
581
  * Function type for retrieving flows based on flow ID and client ID.
@@ -454,6 +611,8 @@ type FlowsFunction = (flowId: string, clientId: string | null) => Effect.Effect<
454
611
  * @template TRequest - Framework-specific request type
455
612
  * @template TResponse - Framework-specific response type
456
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
457
616
  *
458
617
  * @example
459
618
  * ```typescript
@@ -478,7 +637,7 @@ type FlowsFunction = (flowId: string, clientId: string | null) => Effect.Effect<
478
637
  * const server = await createUploadistaServer(config);
479
638
  * ```
480
639
  */
481
- interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
640
+ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown, TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<Flow<z.ZodSchema<unknown>, z.ZodSchema<unknown>, any>, UploadistaError$1, any> = any, TPlugins extends readonly PluginLayer[] = readonly PluginLayer[]> {
482
641
  /**
483
642
  * Function for retrieving flows by ID.
484
643
  *
@@ -491,7 +650,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
491
650
  * flows: (flowId, clientId) => Effect.succeed(myFlows[flowId])
492
651
  * ```
493
652
  */
494
- flows: FlowsFunction;
653
+ flows: TFlows;
495
654
  /**
496
655
  * Data store configuration for file storage.
497
656
  *
@@ -535,7 +694,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
535
694
  * plugins: [imageProcessingPlugin, virusScanPlugin]
536
695
  * ```
537
696
  */
538
- plugins?: readonly Layer.Layer<any, never, never>[];
697
+ plugins?: TPlugins;
539
698
  /**
540
699
  * Optional: Event emitter layer for progress notifications.
541
700
  *
@@ -611,7 +770,7 @@ interface UploadistaServerConfig<TRequest, TResponse, TWebSocket = unknown> {
611
770
  * metricsLayer: prometheusMetrics()
612
771
  * ```
613
772
  */
614
- metricsLayer?: Layer.Layer<any, never, never>;
773
+ metricsLayer?: Layer.Layer<MetricsService, never, never>;
615
774
  /**
616
775
  * Optional: Buffered data store layer for performance optimization.
617
776
  *
@@ -689,29 +848,398 @@ interface UploadistaServer<TRequest, TResponse, TWebSocketHandler = unknown> {
689
848
  dispose: () => Promise<void>;
690
849
  }
691
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
692
1139
  //#region src/core/server.d.ts
693
1140
  /**
694
1141
  * Creates the unified Uploadista server with framework-specific adapter.
695
1142
  *
696
- * This function composes all layers (upload server, flow server, auth, metrics)
697
- * 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
698
1147
  *
699
- * The core server handles:
1148
+ * The server handles:
1149
+ * - Layer composition (upload/flow servers, auth cache, metrics, plugins)
700
1150
  * - Route parsing and matching
701
1151
  * - Auth middleware execution with timeout protection
702
- * - Layer composition (upload/flow servers, auth cache, metrics)
703
1152
  * - Error handling and response formatting
704
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
705
1231
  *
706
1232
  * @param config - Server configuration including adapter and business logic
707
- * @returns Object with handler function, optional WebSocket handler, and base URL
1233
+ * @returns Promise resolving to server instance with handler and metadata
708
1234
  *
709
- * @example
1235
+ * @example Basic Usage
710
1236
  * ```typescript
711
1237
  * import { createUploadistaServer, honoAdapter } from "@uploadista/server";
1238
+ * import { sharpImagePlugin } from "@uploadista/flow-images-sharp";
712
1239
  *
713
1240
  * const server = await createUploadistaServer({
714
1241
  * flows: getFlowById,
1242
+ * plugins: [sharpImagePlugin],
715
1243
  * dataStore: { type: "s3", config: { bucket: "uploads" } },
716
1244
  * kvStore: redisKvStore,
717
1245
  * adapter: honoAdapter({
@@ -722,8 +1250,32 @@ interface UploadistaServer<TRequest, TResponse, TWebSocketHandler = unknown> {
722
1250
  * // Use with Hono
723
1251
  * app.all("/uploadista/*", server.handler);
724
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
725
1277
  */
726
- 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<z.ZodSchema<unknown>, z.ZodSchema<unknown>, any>, UploadistaError$1, any> = any, TPlugins extends readonly PluginLayer[] = readonly PluginLayer[]>({
727
1279
  flows,
728
1280
  dataStore,
729
1281
  kvStore,
@@ -737,7 +1289,7 @@ declare const createUploadistaServer: <TContext, TResponse, TWebSocketHandler =
737
1289
  bufferedDataStore,
738
1290
  adapter,
739
1291
  authCacheConfig
740
- }: UploadistaServerConfig<TContext, TResponse, TWebSocketHandler>) => Promise<UploadistaServer<TContext, TResponse, TWebSocketHandler>>;
1292
+ }: UploadistaServerConfig<TContext, TResponse, TWebSocketHandler, TFlows, TPlugins>) => Promise<UploadistaServer<TContext, TResponse, TWebSocketHandler>>;
741
1293
  //#endregion
742
1294
  //#region src/core/websocket-routes.d.ts
743
1295
  /**
@@ -1272,10 +1824,80 @@ declare const createFlowServerLayer: ({
1272
1824
  }: FlowServerLayerConfig) => Layer.Layer<_uploadista_core0.FlowServer, never, never>;
1273
1825
  //#endregion
1274
1826
  //#region src/plugins-typing.d.ts
1275
- 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
+ */
1276
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
+ */
1277
1866
  type FlowRequirementsOf<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = FlowSuccess<TFlows> extends Flow$1<z$1.ZodSchema<unknown>, z$1.ZodSchema<unknown>, infer R> ? Exclude<R, UploadServer$1> : 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
+ */
1278
1883
  type RequiredPluginsOf<TFlows extends (flowId: string, clientId: string | null) => Effect.Effect<unknown, unknown, unknown>> = Exclude<FlowRequirementsOf<TFlows>, UploadServer$1>;
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
+ */
1279
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 : {
1280
1902
  __missingPlugins: Exclude<RequiredPluginsOf<TFlows>, LayerSuccessUnion<TPlugins>>;
1281
1903
  };
@@ -1340,5 +1962,5 @@ declare const AuthContextServiceLive: (authContext: AuthContext | null) => Layer
1340
1962
  */
1341
1963
  declare const NoAuthContextServiceLive: Layer.Layer<AuthContextService>;
1342
1964
  //#endregion
1343
- 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 };
1344
1966
  //# sourceMappingURL=index.d.mts.map