@uploadista/server 0.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.
Files changed (91) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +34 -0
  3. package/LICENSE +21 -0
  4. package/README.md +503 -0
  5. package/dist/auth/cache.d.ts +87 -0
  6. package/dist/auth/cache.d.ts.map +1 -0
  7. package/dist/auth/cache.js +121 -0
  8. package/dist/auth/cache.test.d.ts +2 -0
  9. package/dist/auth/cache.test.d.ts.map +1 -0
  10. package/dist/auth/cache.test.js +209 -0
  11. package/dist/auth/get-auth-credentials.d.ts +73 -0
  12. package/dist/auth/get-auth-credentials.d.ts.map +1 -0
  13. package/dist/auth/get-auth-credentials.js +55 -0
  14. package/dist/auth/index.d.ts +2 -0
  15. package/dist/auth/index.d.ts.map +1 -0
  16. package/dist/auth/index.js +1 -0
  17. package/dist/auth/jwt/index.d.ts +38 -0
  18. package/dist/auth/jwt/index.d.ts.map +1 -0
  19. package/dist/auth/jwt/index.js +36 -0
  20. package/dist/auth/jwt/types.d.ts +77 -0
  21. package/dist/auth/jwt/types.d.ts.map +1 -0
  22. package/dist/auth/jwt/types.js +1 -0
  23. package/dist/auth/jwt/validate.d.ts +58 -0
  24. package/dist/auth/jwt/validate.d.ts.map +1 -0
  25. package/dist/auth/jwt/validate.js +226 -0
  26. package/dist/auth/jwt/validate.test.d.ts +2 -0
  27. package/dist/auth/jwt/validate.test.d.ts.map +1 -0
  28. package/dist/auth/jwt/validate.test.js +492 -0
  29. package/dist/auth/service.d.ts +63 -0
  30. package/dist/auth/service.d.ts.map +1 -0
  31. package/dist/auth/service.js +43 -0
  32. package/dist/auth/service.test.d.ts +2 -0
  33. package/dist/auth/service.test.d.ts.map +1 -0
  34. package/dist/auth/service.test.js +195 -0
  35. package/dist/auth/types.d.ts +38 -0
  36. package/dist/auth/types.d.ts.map +1 -0
  37. package/dist/auth/types.js +1 -0
  38. package/dist/cache.d.ts +87 -0
  39. package/dist/cache.d.ts.map +1 -0
  40. package/dist/cache.js +121 -0
  41. package/dist/cache.test.d.ts +2 -0
  42. package/dist/cache.test.d.ts.map +1 -0
  43. package/dist/cache.test.js +209 -0
  44. package/dist/cloudflare-config.d.ts +72 -0
  45. package/dist/cloudflare-config.d.ts.map +1 -0
  46. package/dist/cloudflare-config.js +67 -0
  47. package/dist/error-types.d.ts +138 -0
  48. package/dist/error-types.d.ts.map +1 -0
  49. package/dist/error-types.js +155 -0
  50. package/dist/hono-adapter.d.ts +48 -0
  51. package/dist/hono-adapter.d.ts.map +1 -0
  52. package/dist/hono-adapter.js +58 -0
  53. package/dist/http-utils.d.ts +148 -0
  54. package/dist/http-utils.d.ts.map +1 -0
  55. package/dist/http-utils.js +233 -0
  56. package/dist/index.d.ts +9 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +8 -0
  59. package/dist/layer-utils.d.ts +121 -0
  60. package/dist/layer-utils.d.ts.map +1 -0
  61. package/dist/layer-utils.js +80 -0
  62. package/dist/metrics/service.d.ts +26 -0
  63. package/dist/metrics/service.d.ts.map +1 -0
  64. package/dist/metrics/service.js +20 -0
  65. package/dist/plugins-typing.d.ts +11 -0
  66. package/dist/plugins-typing.d.ts.map +1 -0
  67. package/dist/plugins-typing.js +1 -0
  68. package/dist/service.d.ts +63 -0
  69. package/dist/service.d.ts.map +1 -0
  70. package/dist/service.js +43 -0
  71. package/dist/service.test.d.ts +2 -0
  72. package/dist/service.test.d.ts.map +1 -0
  73. package/dist/service.test.js +195 -0
  74. package/dist/types.d.ts +38 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +1 -0
  77. package/package.json +47 -0
  78. package/src/auth/get-auth-credentials.ts +97 -0
  79. package/src/auth/index.ts +1 -0
  80. package/src/cache.test.ts +306 -0
  81. package/src/cache.ts +204 -0
  82. package/src/error-types.ts +172 -0
  83. package/src/http-utils.ts +264 -0
  84. package/src/index.ts +8 -0
  85. package/src/layer-utils.ts +184 -0
  86. package/src/plugins-typing.ts +57 -0
  87. package/src/service.test.ts +275 -0
  88. package/src/service.ts +78 -0
  89. package/src/types.ts +40 -0
  90. package/tsconfig.json +13 -0
  91. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @uploadista/server@0.0.2 build /Users/denislaboureyras/Documents/uploadista/dev/uploadista-workspace/uploadista-sdk/packages/servers/server
4
+ > tsc -b
5
+
@@ -0,0 +1,34 @@
1
+
2
+ > @uploadista/server@ check /Users/denislaboureyras/Documents/uploadista/dev/uploadista/packages/uploadista/servers/server
3
+ > biome check --write ./src
4
+
5
+ src/cloudflare-config.ts:15:55 lint/suspicious/noExplicitAny ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
6
+
7
+ ! Unexpected any. Specify a different type.
8
+
9
+ 13 │ STORAGE_ENCRYPTION_KEY: string;
10
+ 14 │ STORAGE_ENCRYPTION_IV_LENGTH: string;
11
+ > 15 │ UPLOAD_EVENT_DURABLE_OBJECT: DurableObjectNamespace<any>;
12
+ │ ^^^
13
+ 16 │ };
14
+ 17 │
15
+
16
+ i any disables many type checking rules. Its use should be avoided.
17
+
18
+
19
+ src/cloudflare-config.ts:31:16 lint/suspicious/noExplicitAny ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20
+
21
+ ! Unexpected any. Specify a different type.
22
+
23
+ 29 │ storageIvLength?: string;
24
+ 30 │ },
25
+ > 31 │ ) => Promise<any>;
26
+ │ ^^^
27
+ 32 │ };
28
+ 33 │
29
+
30
+ Checked 2 files in 36ms. No fixes applied.
31
+ Found 2 warnings.
32
+ i any disables many type checking rules. Its use should be avoided.
33
+
34
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,503 @@
1
+ # @uploadista/server
2
+
3
+ Core server utilities and authentication for Uploadista file upload and flow processing.
4
+
5
+ This package provides framework-agnostic server components including authentication context management, caching utilities, and layer composition helpers. Use this with adapter packages (`@uploadista/adapters-hono`, `@uploadista/adapters-express`, `@uploadista/adapters-fastify`) to set up complete upload servers.
6
+
7
+ ## Features
8
+
9
+ - **Authentication Context** - User identity and metadata management
10
+ - **Auth Caching** - LRU cache for auth contexts with TTL support
11
+ - **Effect Layers** - Dependency injection for upload and flow servers
12
+ - **Error Handling** - Standardized error responses with HTTP status codes
13
+ - **HTTP Utilities** - Route parsing and error mapping helpers
14
+ - **TypeScript** - Full type safety with comprehensive JSDoc
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @uploadista/server @uploadista/core
20
+ # or
21
+ pnpm add @uploadista/server @uploadista/core
22
+ ```
23
+
24
+ ## Requirements
25
+
26
+ - Node.js 18+
27
+ - TypeScript 5.0+ (optional but recommended)
28
+
29
+ ## Quick Start
30
+
31
+ ### 1. Set Up Authentication
32
+
33
+ ```typescript
34
+ import { AuthContextServiceLive } from "@uploadista/server";
35
+ import { Effect } from "effect";
36
+
37
+ // Create auth context for a request
38
+ const authContext = {
39
+ clientId: "user-123",
40
+ metadata: {
41
+ permissions: ["upload:create", "flow:execute"],
42
+ quota: { storage: 1000000000 }, // 1GB
43
+ },
44
+ };
45
+
46
+ // Provide auth context to your effects
47
+ const effect = Effect.service(AuthContextService).pipe(
48
+ Effect.andThen((authService) => authService.getClientId()),
49
+ );
50
+
51
+ const result = await Effect.runPromise(
52
+ effect.pipe(Effect.provide(AuthContextServiceLive(authContext))),
53
+ );
54
+ console.log(result); // "user-123"
55
+ ```
56
+
57
+ ### 2. Get JWT Credentials
58
+
59
+ ```typescript
60
+ import { getAuthCredentials } from "@uploadista/server";
61
+
62
+ // Exchange credentials for JWT token
63
+ const response = await getAuthCredentials({
64
+ uploadistaClientId: process.env.UPLOADISTA_CLIENT_ID,
65
+ uploadistaApiKey: process.env.UPLOADISTA_API_KEY,
66
+ });
67
+
68
+ if (response.isValid) {
69
+ console.log(`Token: ${response.data.token}`);
70
+ console.log(`Expires in: ${response.data.expiresIn}s`);
71
+ } else {
72
+ console.error(`Auth failed: ${response.error}`);
73
+ }
74
+ ```
75
+
76
+ ### 3. Create Upload Server Layer
77
+
78
+ ```typescript
79
+ import { createUploadServerLayer } from "@uploadista/server";
80
+ import { redisKvStore } from "@uploadista/kv-store-redis";
81
+ import { s3DataStore } from "@uploadista/data-store-s3";
82
+ import { webSocketEventEmitter } from "@uploadista/event-emitter-websocket";
83
+ import { memoryEventBroadcaster } from "@uploadista/event-broadcaster-memory";
84
+
85
+ const uploadServerLayer = createUploadServerLayer({
86
+ kvStore: redisKvStore,
87
+ eventEmitter: webSocketEventEmitter,
88
+ dataStore: s3DataStore,
89
+ });
90
+
91
+ // Use in your framework adapter...
92
+ ```
93
+
94
+ ### 4. Create Flow Server Layer
95
+
96
+ ```typescript
97
+ import { createFlowServerLayer } from "@uploadista/server";
98
+
99
+ const flowServerLayer = createFlowServerLayer({
100
+ kvStore: redisKvStore,
101
+ eventEmitter: webSocketEventEmitter,
102
+ flowProvider: createFlowsEffect,
103
+ uploadServer: uploadServerLayer,
104
+ });
105
+
106
+ // Use in your framework adapter...
107
+ ```
108
+
109
+ ## API Reference
110
+
111
+ ### Authentication
112
+
113
+ #### `AuthContext`
114
+
115
+ User identity and authorization metadata.
116
+
117
+ ```typescript
118
+ type AuthContext = {
119
+ clientId: string;
120
+ metadata?: Record<string, unknown>;
121
+ permissions?: string[];
122
+ };
123
+ ```
124
+
125
+ **Properties**:
126
+ - `clientId` - Unique user identifier
127
+ - `metadata` - Custom authorization metadata (permissions, quotas, etc.)
128
+ - `permissions` - Array of permission strings for authorization
129
+
130
+ #### `AuthContextService`
131
+
132
+ Effect service for accessing auth context throughout request processing.
133
+
134
+ ```typescript
135
+ export class AuthContextService extends Context.Tag("AuthContextService")<
136
+ AuthContextService,
137
+ {
138
+ readonly getClientId: () => Effect.Effect<string | null>;
139
+ readonly getMetadata: () => Effect.Effect<Record<string, unknown>>;
140
+ readonly hasPermission: (permission: string) => Effect.Effect<boolean>;
141
+ readonly getAuthContext: () => Effect.Effect<AuthContext | null>;
142
+ }
143
+ >() {}
144
+ ```
145
+
146
+ **Methods**:
147
+ - `getClientId()` - Get current client ID
148
+ - `getMetadata()` - Get auth metadata object
149
+ - `hasPermission(permission)` - Check if user has permission
150
+ - `getAuthContext()` - Get full auth context
151
+
152
+ #### `AuthContextServiceLive(authContext)`
153
+
154
+ Factory for creating AuthContextService layer.
155
+
156
+ ```typescript
157
+ import { AuthContextServiceLive } from "@uploadista/server";
158
+
159
+ const authLayer = AuthContextServiceLive({
160
+ clientId: "user-123",
161
+ permissions: ["upload:create"],
162
+ });
163
+ ```
164
+
165
+ #### `getAuthCredentials(params)`
166
+
167
+ Exchange client credentials for JWT token.
168
+
169
+ ```typescript
170
+ import { getAuthCredentials } from "@uploadista/server";
171
+
172
+ const response = await getAuthCredentials({
173
+ uploadistaClientId: "my-client",
174
+ uploadistaApiKey: "sk_...",
175
+ baseUrl: "https://api.uploadista.com", // optional
176
+ });
177
+
178
+ if (response.isValid) {
179
+ // response.data.token - JWT token
180
+ // response.data.expiresIn - Seconds until expiration
181
+ } else {
182
+ // response.error - Error message
183
+ }
184
+ ```
185
+
186
+ ### Caching
187
+
188
+ #### `AuthCacheConfig`
189
+
190
+ Configuration for auth context caching.
191
+
192
+ ```typescript
193
+ type AuthCacheConfig = {
194
+ maxSize?: number; // Default: 10000
195
+ ttl?: number; // Default: 3600000 (1 hour)
196
+ };
197
+ ```
198
+
199
+ #### `AuthCacheService`
200
+
201
+ Effect service for storing and retrieving cached auth contexts.
202
+
203
+ ```typescript
204
+ export class AuthCacheService extends Context.Tag("AuthCacheService")<
205
+ AuthCacheService,
206
+ {
207
+ readonly set: (
208
+ jobId: string,
209
+ authContext: AuthContext,
210
+ ) => Effect.Effect<void>;
211
+ readonly get: (jobId: string) => Effect.Effect<AuthContext | null>;
212
+ readonly delete: (jobId: string) => Effect.Effect<void>;
213
+ readonly clear: () => Effect.Effect<void>;
214
+ readonly size: () => Effect.Effect<number>;
215
+ }
216
+ >() {}
217
+ ```
218
+
219
+ **Methods**:
220
+ - `set(jobId, authContext)` - Cache auth for a job
221
+ - `get(jobId)` - Retrieve cached auth
222
+ - `delete(jobId)` - Remove specific cache entry
223
+ - `clear()` - Clear all cached entries
224
+ - `size()` - Get number of cached entries
225
+
226
+ #### `AuthCacheServiceLive(config?)`
227
+
228
+ Create in-memory auth cache layer.
229
+
230
+ ```typescript
231
+ import { AuthCacheServiceLive } from "@uploadista/server";
232
+
233
+ const cacheLayer = AuthCacheServiceLive({
234
+ maxSize: 5000,
235
+ ttl: 1800000, // 30 minutes
236
+ });
237
+ ```
238
+
239
+ ### Layer Composition
240
+
241
+ #### `UploadServerLayerConfig`
242
+
243
+ Configuration for creating upload server layer.
244
+
245
+ ```typescript
246
+ interface UploadServerLayerConfig {
247
+ kvStore: Layer.Layer<BaseKvStoreService>;
248
+ eventEmitter: Layer.Layer<BaseEventEmitterService>;
249
+ dataStore: Layer.Layer<UploadFileDataStores, never, UploadFileKVStore>;
250
+ bufferedDataStore?: Layer.Layer<UploadFileDataStore>;
251
+ generateId?: Layer.Layer<GenerateId>;
252
+ }
253
+ ```
254
+
255
+ #### `createUploadServerLayer(config)`
256
+
257
+ Compose upload server with all dependencies.
258
+
259
+ ```typescript
260
+ import { createUploadServerLayer } from "@uploadista/server";
261
+
262
+ const uploadLayer = createUploadServerLayer({
263
+ kvStore: redisKvStore,
264
+ eventEmitter: webSocketEventEmitter,
265
+ dataStore: s3DataStore,
266
+ });
267
+ ```
268
+
269
+ #### `FlowServerLayerConfig`
270
+
271
+ Configuration for creating flow server layer.
272
+
273
+ ```typescript
274
+ interface FlowServerLayerConfig {
275
+ kvStore: Layer.Layer<BaseKvStoreService>;
276
+ eventEmitter: Layer.Layer<BaseEventEmitterService>;
277
+ flowProvider: Layer.Layer<FlowProvider>;
278
+ uploadServer: Layer.Layer<UploadServer>;
279
+ }
280
+ ```
281
+
282
+ #### `createFlowServerLayer(config)`
283
+
284
+ Compose flow server with all dependencies.
285
+
286
+ ```typescript
287
+ import { createFlowServerLayer } from "@uploadista/server";
288
+
289
+ const flowLayer = createFlowServerLayer({
290
+ kvStore: redisKvStore,
291
+ eventEmitter: webSocketEventEmitter,
292
+ flowProvider: createFlowsEffect,
293
+ uploadServer: uploadLayer,
294
+ });
295
+ ```
296
+
297
+ ### Error Handling
298
+
299
+ #### `AdapterError`
300
+
301
+ Base error class for adapter errors.
302
+
303
+ ```typescript
304
+ class AdapterError extends Error {
305
+ constructor(
306
+ message: string,
307
+ statusCode?: number,
308
+ errorCode?: string,
309
+ ) {}
310
+ }
311
+ ```
312
+
313
+ **Properties**:
314
+ - `statusCode` - HTTP status code (default: 500)
315
+ - `errorCode` - Machine-readable error code
316
+
317
+ #### `ValidationError`, `NotFoundError`, `BadRequestError`
318
+
319
+ Pre-configured error classes:
320
+
321
+ ```typescript
322
+ import {
323
+ ValidationError,
324
+ NotFoundError,
325
+ BadRequestError,
326
+ } from "@uploadista/server";
327
+
328
+ // Validation error (400)
329
+ throw new ValidationError("Invalid upload ID format");
330
+
331
+ // Not found (404)
332
+ throw new NotFoundError("Upload");
333
+
334
+ // Bad request (400)
335
+ throw new BadRequestError("Invalid JSON body");
336
+ ```
337
+
338
+ #### Error Response Factories
339
+
340
+ ```typescript
341
+ import {
342
+ createErrorResponseBody,
343
+ createUploadistaErrorResponseBody,
344
+ createGenericErrorResponseBody,
345
+ } from "@uploadista/server";
346
+
347
+ // For adapter errors
348
+ const errorResponse = createErrorResponseBody(
349
+ new ValidationError("Invalid data"),
350
+ );
351
+ // => { error: "Invalid data", code: "VALIDATION_ERROR", timestamp: "..." }
352
+
353
+ // For core library errors
354
+ const uploadistaErrorResponse = createUploadistaErrorResponseBody(error);
355
+
356
+ // For unknown errors
357
+ const genericErrorResponse = createGenericErrorResponseBody("Something went wrong");
358
+ ```
359
+
360
+ ### HTTP Utilities
361
+
362
+ ```typescript
363
+ import {
364
+ parseUrlSegments,
365
+ getLastSegment,
366
+ hasBasePath,
367
+ getRouteSegments,
368
+ handleFlowError,
369
+ extractJobIdFromStatus,
370
+ extractJobAndNodeId,
371
+ extractFlowAndStorageId,
372
+ } from "@uploadista/server";
373
+
374
+ // Parse route
375
+ const segments = parseUrlSegments("/uploadista/api/upload/abc");
376
+ // => ["uploadista", "api", "upload", "abc"]
377
+
378
+ // Check if request is for uploadista
379
+ const isUploadistaRequest = hasBasePath("/uploadista/api/upload", "uploadista");
380
+ // => true
381
+
382
+ // Extract parameters from URL
383
+ const jobId = extractJobIdFromStatus(["jobs", "job-123", "status"]);
384
+ // => "job-123"
385
+
386
+ // Handle errors consistently
387
+ const errorInfo = handleFlowError({
388
+ code: "FILE_NOT_FOUND",
389
+ message: "File not found",
390
+ });
391
+ // => { status: 404, code: "FILE_NOT_FOUND", message: "File not found" }
392
+ ```
393
+
394
+ ## Framework Integration
395
+
396
+ This package is used by framework adapters:
397
+
398
+ - **[@uploadista/adapters-hono](../adapters-hono/)** - For Cloudflare Workers
399
+ - **[@uploadista/adapters-express](../adapters-express/)** - For Node.js Express
400
+ - **[@uploadista/adapters-fastify](../adapters-fastify/)** - For Node.js Fastify
401
+
402
+ ## Complete Server Example
403
+
404
+ ```typescript
405
+ import { Effect, Layer } from "effect";
406
+ import {
407
+ createUploadServerLayer,
408
+ createFlowServerLayer,
409
+ AuthContextServiceLive,
410
+ } from "@uploadista/server";
411
+ import { redisKvStore } from "@uploadista/kv-store-redis";
412
+ import { s3DataStore } from "@uploadista/data-store-s3";
413
+ import { webSocketEventEmitter } from "@uploadista/event-emitter-websocket";
414
+
415
+ // Configure servers
416
+ const uploadLayer = createUploadServerLayer({
417
+ kvStore: redisKvStore,
418
+ eventEmitter: webSocketEventEmitter,
419
+ dataStore: s3DataStore,
420
+ });
421
+
422
+ const flowLayer = createFlowServerLayer({
423
+ kvStore: redisKvStore,
424
+ eventEmitter: webSocketEventEmitter,
425
+ flowProvider: createFlowsEffect,
426
+ uploadServer: uploadLayer,
427
+ });
428
+
429
+ // Set up authentication for a request
430
+ const authContext = {
431
+ clientId: "user-123",
432
+ permissions: ["upload:create", "flow:execute"],
433
+ };
434
+
435
+ // Compose all layers
436
+ const appLayer = Layer.provide(flowLayer, uploadLayer).pipe(
437
+ Layer.provide(AuthContextServiceLive(authContext)),
438
+ );
439
+
440
+ // Run effects
441
+ const myEffect = Effect.gen(function* () {
442
+ const uploadServer = yield* UploadServer;
443
+ const flowServer = yield* FlowServer;
444
+ // ... use uploadServer and flowServer
445
+ });
446
+
447
+ Effect.runPromise(myEffect.pipe(Effect.provide(appLayer)));
448
+ ```
449
+
450
+ ## TypeScript Support
451
+
452
+ Full TypeScript support with comprehensive types:
453
+
454
+ ```typescript
455
+ import type {
456
+ AuthContext,
457
+ AuthResult,
458
+ AuthCacheConfig,
459
+ UploadServerLayerConfig,
460
+ FlowServerLayerConfig,
461
+ } from "@uploadista/server";
462
+ import type { UploadServer, FlowServer } from "@uploadista/core";
463
+ ```
464
+
465
+ ## Architecture Notes
466
+
467
+ ### Authentication Flow
468
+
469
+ 1. Client authenticates with credentials (ID + API key)
470
+ 2. Server validates and issues JWT token
471
+ 3. Token includes user identity and permissions
472
+ 4. Subsequent requests include token in Authorization header
473
+ 5. Auth context created from token claims
474
+ 6. Auth context passed through Effect layers to handlers
475
+ 7. Handlers check permissions before processing
476
+
477
+ ### Effect Layer Pattern
478
+
479
+ - Use `Layer.provide()` to compose dependencies
480
+ - Each layer provides one service (UploadServer, FlowServer, etc.)
481
+ - Auth context automatically available via AuthContextService
482
+ - Cache automatically handles auth context persistence across requests
483
+
484
+ ### Error Handling Strategy
485
+
486
+ 1. Catch domain errors in handlers
487
+ 2. Map to AdapterError with appropriate HTTP status
488
+ 3. Format using createErrorResponseBody
489
+ 4. Return JSON error response with timestamp
490
+ 5. Log errors for monitoring
491
+
492
+ ## Related Packages
493
+
494
+ - **[@uploadista/core](../../core/)** - Core upload and flow engine
495
+ - **[@uploadista/adapters-hono](../adapters-hono/)** - Hono adapter
496
+ - **[@uploadista/adapters-express](../adapters-express/)** - Express adapter
497
+ - **[@uploadista/adapters-fastify](../adapters-fastify/)** - Fastify adapter
498
+ - **[@uploadista/kv-store-redis](../../kv-stores/redis/)** - Redis KV store
499
+ - **[@uploadista/data-store-s3](../../data-stores/s3/)** - AWS S3 storage
500
+
501
+ ## License
502
+
503
+ MIT
@@ -0,0 +1,87 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { AuthContext } from "./types";
3
+ /**
4
+ * Configuration options for the auth cache.
5
+ */
6
+ export type AuthCacheConfig = {
7
+ /**
8
+ * Maximum number of entries in the cache.
9
+ * When exceeded, oldest entries are removed (LRU eviction).
10
+ * @default 10000
11
+ */
12
+ maxSize?: number;
13
+ /**
14
+ * Time-to-live for cache entries in milliseconds.
15
+ * Entries older than this will be automatically evicted.
16
+ * @default 3600000 (1 hour)
17
+ */
18
+ ttl?: number;
19
+ };
20
+ declare const AuthCacheService_base: Context.TagClass<AuthCacheService, "AuthCacheService", {
21
+ /**
22
+ * Store an auth context for a job ID.
23
+ */
24
+ readonly set: (jobId: string, authContext: AuthContext) => Effect.Effect<void>;
25
+ /**
26
+ * Retrieve a cached auth context by job ID.
27
+ * Returns null if not found or expired.
28
+ */
29
+ readonly get: (jobId: string) => Effect.Effect<AuthContext | null>;
30
+ /**
31
+ * Delete a cached auth context by job ID.
32
+ */
33
+ readonly delete: (jobId: string) => Effect.Effect<void>;
34
+ /**
35
+ * Clear all cached auth contexts.
36
+ */
37
+ readonly clear: () => Effect.Effect<void>;
38
+ /**
39
+ * Get the current number of cached entries.
40
+ */
41
+ readonly size: () => Effect.Effect<number>;
42
+ }>;
43
+ /**
44
+ * Auth Cache Service
45
+ *
46
+ * Provides caching of authentication contexts for upload and flow jobs.
47
+ * This allows subsequent operations (chunk uploads, flow continuations)
48
+ * to reuse the auth context from the initial request without re-authenticating.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { Effect } from "effect";
53
+ * import { AuthCacheService } from "@uploadista/server";
54
+ *
55
+ * const handler = Effect.gen(function* () {
56
+ * const authCache = yield* AuthCacheService;
57
+ * const authContext = { userId: "user-123" };
58
+ *
59
+ * // Cache auth for upload
60
+ * yield* authCache.set("upload-abc", authContext);
61
+ *
62
+ * // Retrieve cached auth later
63
+ * const cached = yield* authCache.get("upload-abc");
64
+ * console.log(cached?.userId); // "user-123"
65
+ *
66
+ * // Clear when done
67
+ * yield* authCache.delete("upload-abc");
68
+ * });
69
+ * ```
70
+ */
71
+ export declare class AuthCacheService extends AuthCacheService_base {
72
+ }
73
+ /**
74
+ * Creates an AuthCacheService Layer with in-memory storage.
75
+ *
76
+ * @param config - Optional configuration for cache behavior
77
+ * @returns Effect Layer providing AuthCacheService
78
+ */
79
+ export declare const AuthCacheServiceLive: (config?: AuthCacheConfig) => Layer.Layer<AuthCacheService>;
80
+ /**
81
+ * No-op implementation of AuthCacheService.
82
+ * Does not cache anything - all operations are no-ops.
83
+ * Used when caching is disabled or not needed.
84
+ */
85
+ export declare const NoAuthCacheServiceLive: Layer.Layer<AuthCacheService>;
86
+ export {};
87
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/auth/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;;IAyCE;;OAEG;kBACW,CACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,WAAW,KACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAExB;;;OAGG;kBACW,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;IAElE;;OAEG;qBACc,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAEvD;;OAEG;oBACa,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAEzC;;OAEG;mBACY,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;;AA1D9C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,gBAAiB,SAAQ,qBAgCnC;CAAG;AAEN;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,eAAoB,KAC3B,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAyF9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAO7D,CAAC"}