@uploadista/server 0.0.8 → 0.0.10

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 (37) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/auth/index.d.mts +2 -0
  3. package/dist/auth/index.mjs +1 -0
  4. package/dist/{auth-C77S4vQd.js → auth-BqArZeGK.mjs} +1 -1
  5. package/dist/auth-BqArZeGK.mjs.map +1 -0
  6. package/dist/{index-CvDNB1lJ.d.ts → index--Lny6VJP.d.mts} +1 -1
  7. package/dist/index--Lny6VJP.d.mts.map +1 -0
  8. package/dist/index.cjs +1 -1
  9. package/dist/index.d.cts +734 -10
  10. package/dist/index.d.cts.map +1 -1
  11. package/dist/index.d.mts +1344 -0
  12. package/dist/index.d.mts.map +1 -0
  13. package/dist/index.mjs +2 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +18 -13
  16. package/src/adapter/index.ts +10 -0
  17. package/src/adapter/types.ts +229 -0
  18. package/src/core/http-handlers/flow-http-handlers.ts +245 -0
  19. package/src/core/http-handlers/http-handlers.ts +72 -0
  20. package/src/core/http-handlers/upload-http-handlers.ts +168 -0
  21. package/src/core/index.ts +12 -0
  22. package/src/core/routes.ts +188 -0
  23. package/src/core/server.ts +327 -0
  24. package/src/core/types.ts +322 -0
  25. package/src/core/websocket-handlers/flow-websocket-handlers.ts +47 -0
  26. package/src/core/websocket-handlers/upload-websocket-handlers.ts +47 -0
  27. package/src/core/websocket-handlers/websocket-handlers.ts +151 -0
  28. package/src/core/websocket-routes.ts +136 -0
  29. package/src/index.ts +2 -0
  30. package/dist/auth/index.d.ts +0 -2
  31. package/dist/auth/index.js +0 -1
  32. package/dist/auth-C77S4vQd.js.map +0 -1
  33. package/dist/index-CvDNB1lJ.d.ts.map +0 -1
  34. package/dist/index.d.ts +0 -620
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.js +0 -2
  37. package/dist/index.js.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,69 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@uploadista/server` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - **Unified Adapter Pattern**: Introduced `ServerAdapter<TContext, TResponse, TWebSocket>` interface to standardize framework integration
13
+ - **Core Server Implementation**: Added `createUploadistaServer()` function that handles all common server logic:
14
+ - Route parsing and request type determination
15
+ - Auth middleware execution with 5-second timeout protection
16
+ - Layer composition (upload server, flow server, auth, metrics, plugins)
17
+ - Error handling with `handleFlowError()` utility
18
+ - Effect program execution with optional tracing support
19
+ - **Adapter Interface Types** in `src/adapter/types.ts`:
20
+ - `StandardRequest` - Framework-agnostic request representation
21
+ - `StandardResponse` - Framework-agnostic response representation
22
+ - `WebSocketHandler` - Framework-agnostic WebSocket interface
23
+ - `ServerAdapter` - Interface that framework adapters must implement
24
+ - **Core Server Types** in `src/core/types.ts`:
25
+ - `UploadistaServerConfig` - Configuration for unified server
26
+ - `UploadistaServer` - Return type with handler, websocketHandler, and dispose
27
+ - **Typed Request/Response Routes** in `src/core/routes.ts`:
28
+ - Strongly-typed route definitions for all endpoints (upload, flow, jobs)
29
+ - Request types: `CreateUploadRequest`, `GetUploadRequest`, `UploadChunkRequest`, etc.
30
+ - Response types: `CreateUploadResponse`, `GetUploadResponse`, etc.
31
+ - Error types: `NotFoundRequest`, `BadRequestRequest`, `MethodNotAllowedRequest`
32
+ - **HTTP Handlers** in `src/core/http-handlers/`:
33
+ - `handleUploadistaRequest()` - Central request router
34
+ - Upload handlers: `handleCreateUpload()`, `handleGetUpload()`, `handleUploadChunk()`, `handleGetCapabilities()`
35
+ - Flow handlers: `handleGetFlow()`, `handleRunFlow()`, `handleJobStatus()`, `handleResumeFlow()`, `handlePauseFlow()`, `handleCancelFlow()`
36
+ - **WebSocket Handlers** in `src/core/websocket-handlers/`:
37
+ - `handleWebSocketOpen()` - Subscription management
38
+ - `handleWebSocketMessage()` - Message handling (ping/pong)
39
+ - `handleWebSocketClose()` - Cleanup and unsubscription
40
+ - `handleWebSocketError()` - Error logging
41
+ - **Managed Runtime**: Uses Effect's `ManagedRuntime` for proper resource lifecycle management
42
+ - **Auth Cache Support**: Configurable auth caching via `AuthCacheConfig`
43
+
44
+ ### Changed
45
+
46
+ - **Architecture**: Moved from adapter-specific implementations to centralized core server
47
+ - **Layer Composition**: Now handled uniformly in core server instead of each adapter
48
+ - **Error Handling**: Standardized via `handleFlowError()` across all adapters
49
+ - **Request Routing**: Delegated to adapters via `extractRequest()` returning typed `UploadistaRequest` objects
50
+
51
+ ### Benefits
52
+
53
+ - **Code Reduction**: Eliminates ~80% code duplication across framework adapters
54
+ - **Consistency**: All frameworks guaranteed identical routing, auth, and error handling behavior
55
+ - **Maintainability**: Bug fixes and features only need to be implemented once
56
+ - **Testability**: Core logic can be tested independently with mock adapters
57
+ - **Extensibility**: New frameworks can be added with ~100-150 lines of adapter code
58
+
59
+ ### Technical Details
60
+
61
+ - Uses Effect.js for composable error handling and layer composition
62
+ - Supports optional OpenTelemetry tracing via `withTracing` flag
63
+ - Integrates with existing observability system (`@uploadista/observability`)
64
+ - Compatible with all event emitters and broadcasters
65
+ - Maintains backward compatibility through separate adapter implementations
66
+
67
+ ## [0.0.8] - Previous Version
68
+
69
+ Initial implementation with framework-specific logic in each adapter.
@@ -0,0 +1,2 @@
1
+ import { n as getAuthCredentials, t as AuthCredentialsResponse } from "../index--Lny6VJP.mjs";
2
+ export { AuthCredentialsResponse, getAuthCredentials };
@@ -0,0 +1 @@
1
+ import{t as e}from"../auth-BqArZeGK.mjs";export{e as getAuthCredentials};
@@ -1,2 +1,2 @@
1
1
  const e=async({uploadistaClientId:e,uploadistaApiKey:t,baseUrl:n=`https://api.uploadista.com`})=>{let r=await fetch(`${n}/uploadista/auth/jwt?apiKey=${t}&clientId=${e}`,{method:`GET`,headers:{"Content-Type":`application/json`}});return r.ok===!0?{isValid:!0,data:await r.json()}:{isValid:!1,error:`Failed to get auth credentials`}};export{e as t};
2
- //# sourceMappingURL=auth-C77S4vQd.js.map
2
+ //# sourceMappingURL=auth-BqArZeGK.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-BqArZeGK.mjs","names":[],"sources":["../src/auth/get-auth-credentials.ts"],"sourcesContent":["/**\n * Response type for authentication credential requests.\n * - `isValid: true` with token and expiration\n * - `isValid: false` with error message\n *\n * @example\n * ```typescript\n * const response = await getAuthCredentials({\n * uploadistaClientId: \"my-client\",\n * uploadistaApiKey: \"sk_...\"\n * });\n * if (response.isValid) {\n * console.log(`Token: ${response.data.token}`);\n * } else {\n * console.error(`Auth failed: ${response.error}`);\n * }\n * ```\n */\nexport type AuthCredentialsResponse =\n | {\n isValid: true;\n data: { token: string; expiresIn: number };\n }\n | {\n isValid: false;\n error: string;\n };\n\n/**\n * Retrieve JWT authentication credentials from the Uploadista server.\n * This function exchanges client credentials (ID + API key) for a signed JWT token.\n *\n * The JWT token is then used in subsequent API requests via the Authorization header.\n * Tokens are time-limited and should be refreshed before expiration.\n *\n * @param params - Credential exchange parameters\n * @param params.uploadistaClientId - Your Uploadista client ID\n * @param params.uploadistaApiKey - Your Uploadista API key (secret)\n * @param params.baseUrl - Uploadista server base URL (default: https://api.uploadista.com)\n * @returns Promise resolving to authentication response with token or error\n *\n * @example\n * ```typescript\n * import { getAuthCredentials } from \"@uploadista/server\";\n *\n * // Get JWT token for API requests\n * const response = await getAuthCredentials({\n * uploadistaClientId: process.env.UPLOADISTA_CLIENT_ID,\n * uploadistaApiKey: process.env.UPLOADISTA_API_KEY,\n * });\n *\n * if (response.isValid) {\n * // Use token in API requests\n * const headers = {\n * Authorization: `Bearer ${response.data.token}`,\n * };\n *\n * // Token expires in response.data.expiresIn seconds\n * setTimeout(\n * () => {\n * // Refresh token before expiration\n * },\n * response.data.expiresIn * 1000,\n * );\n * }\n * ```\n */\nexport const getAuthCredentials = async ({\n uploadistaClientId,\n uploadistaApiKey,\n baseUrl = \"https://api.uploadista.com\",\n}: {\n uploadistaClientId: string;\n uploadistaApiKey: string;\n baseUrl?: string;\n}): Promise<AuthCredentialsResponse> => {\n const response = await fetch(\n `${baseUrl}/uploadista/auth/jwt?apiKey=${uploadistaApiKey}&clientId=${uploadistaClientId}`,\n {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n },\n );\n\n if (response.ok !== true) {\n return { isValid: false, error: \"Failed to get auth credentials\" };\n }\n\n const data = (await response.json()) as { token: string; expiresIn: number };\n\n return {\n isValid: true,\n data,\n };\n};\n"],"mappings":"AAmEA,MAAa,EAAqB,MAAO,CACvC,qBACA,mBACA,UAAU,gCAK4B,CACtC,IAAM,EAAW,MAAM,MACrB,GAAG,EAAQ,8BAA8B,EAAiB,YAAY,IACtE,CACE,OAAQ,MACR,QAAS,CACP,eAAgB,mBACjB,CACF,CACF,CAQD,OANI,EAAS,KAAO,GAMb,CACL,QAAS,GACT,KAJY,MAAM,EAAS,MAAM,CAKlC,CARQ,CAAE,QAAS,GAAO,MAAO,iCAAkC"}
@@ -77,4 +77,4 @@ declare const getAuthCredentials: ({
77
77
  }) => Promise<AuthCredentialsResponse>;
78
78
  //#endregion
79
79
  export { getAuthCredentials as n, AuthCredentialsResponse as t };
80
- //# sourceMappingURL=index-CvDNB1lJ.d.ts.map
80
+ //# sourceMappingURL=index--Lny6VJP.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index--Lny6VJP.d.mts","names":[],"sources":["../src/auth/get-auth-credentials.ts"],"sourcesContent":[],"mappings":";;AAkBA;AAiDA;;;;;;;;;;;;;;;;KAjDY,uBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiDC;;;;;;;;MAQT,QAAQ"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./auth-B3XCQncE.cjs`);let l=require(`effect`);l=s(l);let u=require(`@uploadista/core/flow`);u=s(u);let d=require(`@uploadista/core/types`);d=s(d);let f=require(`@uploadista/core/upload`);f=s(f);var p=class extends l.Context.Tag(`AuthCacheService`)(){};const m=(e={})=>{let t=e.maxSize??1e4,n=e.ttl??36e5,r=new Map,i=()=>{let e=Date.now();for(let[t,i]of r.entries())e-i.timestamp>n&&r.delete(t)},a=()=>{if(r.size<=t)return;let e=null,n=1/0;for(let[t,i]of r.entries())i.timestamp<n&&(n=i.timestamp,e=t);e&&r.delete(e)};return l.Layer.succeed(p,{set:(e,t)=>l.Effect.sync(()=>{r.size%100==0&&i(),r.set(e,{authContext:t,timestamp:Date.now()}),a()}),get:e=>l.Effect.sync(()=>{let t=r.get(e);return t?Date.now()-t.timestamp>n?(r.delete(e),null):t.authContext:null}),delete:e=>l.Effect.sync(()=>{r.delete(e)}),clear:()=>l.Effect.sync(()=>{r.clear()}),size:()=>l.Effect.sync(()=>r.size)})},h=l.Layer.succeed(p,{set:()=>l.Effect.void,get:()=>l.Effect.succeed(null),delete:()=>l.Effect.void,clear:()=>l.Effect.void,size:()=>l.Effect.succeed(0)});var g=class extends Error{constructor(e,t=500,n=`INTERNAL_ERROR`){super(e),this.statusCode=t,this.errorCode=n,this.name=`AdapterError`}},_=class extends g{constructor(e){super(e,400,`VALIDATION_ERROR`),this.name=`ValidationError`}},v=class extends g{constructor(e){super(`${e} not found`,404,`NOT_FOUND`),this.name=`NotFoundError`}},y=class extends g{constructor(e){super(e,400,`BAD_REQUEST`),this.name=`BadRequestError`}};const b=e=>({error:e.message,code:e.errorCode,timestamp:new Date().toISOString()}),x=e=>{let t={error:e.body,code:e.code,timestamp:new Date().toISOString()};return e.details!==void 0&&(t.details=e.details),t},S=(e=`Internal server error`)=>({error:e,code:`INTERNAL_ERROR`,timestamp:new Date().toISOString()}),C=e=>e.split(`/`).filter(Boolean),w=e=>{let t=C(e);return t[t.length-1]},T=(e,t)=>e.includes(`${t}/api/`),E=(e,t)=>e.replace(`${t}/api/`,``).split(`/`).filter(Boolean),D=e=>{let t=500,n=`UNKNOWN_ERROR`,r=`Internal server error`,i;if(typeof e==`object`&&e){let a=e;if(`code`in a&&typeof a.code==`string`&&(n=a.code),`message`in a&&typeof a.message==`string`?r=a.message:`body`in a&&typeof a.body==`string`&&(r=a.body),`details`in a&&(i=a.details),`status`in a&&typeof a.status==`number`)t=a.status;else if(`code`in a)switch(a.code){case`FILE_NOT_FOUND`:case`FLOW_JOB_NOT_FOUND`:case`UPLOAD_ID_NOT_FOUND`:t=404;break;case`FLOW_JOB_ERROR`:case`VALIDATION_ERROR`:case`INVALID_METADATA`:case`INVALID_LENGTH`:case`ABORTED`:case`INVALID_TERMINATION`:t=400;break;case`INVALID_OFFSET`:t=409;break;case`ERR_SIZE_EXCEEDED`:case`ERR_MAX_SIZE_EXCEEDED`:t=413;break;case`FILE_NO_LONGER_EXISTS`:t=410;break;case`MISSING_OFFSET`:case`INVALID_CONTENT_TYPE`:t=403;break;default:t=500}`message`in a&&a.message===`Invalid JSON body`&&(t=400,n=`VALIDATION_ERROR`)}let a={status:t,code:n,message:r};return i!==void 0&&(a.details=i),a},O=e=>e[e.length-2],k=e=>({jobId:e[e.length-3],nodeId:e[e.length-1]}),A=e=>({storageId:e.pop(),flowId:e.pop()}),j=({kvStore:e,eventEmitter:t,dataStore:n,bufferedDataStore:r,generateId:i})=>{let a=l.Layer.provide(d.uploadFileKvStore,e),o=l.Layer.provide(n,a),s=r?l.Layer.provide(r,a):l.Layer.empty,c=l.Layer.provide(d.uploadEventEmitter,t),u=l.Layer.mergeAll(o,a,c,...i?[i]:[],s);return l.Layer.provide(f.uploadServer,u)},M=({kvStore:e,eventEmitter:t,flowProvider:n,uploadServer:r})=>{let i=l.Layer.provide(d.flowJobKvStore,e),a=l.Layer.provide(d.flowEventEmitter,t),o=l.Layer.mergeAll(n,a,i,r);return l.Layer.provide(u.flowServer,o)};var N=class extends l.Context.Tag(`AuthContextService`)(){};const P=e=>l.Layer.succeed(N,{getClientId:()=>l.Effect.succeed(e?.clientId??null),getMetadata:()=>l.Effect.succeed(e?.metadata??{}),hasPermission:t=>l.Effect.succeed(e?.permissions?.includes(t)??!1),getAuthContext:()=>l.Effect.succeed(e)}),F=P(null);exports.AdapterError=g,exports.AuthCacheService=p,exports.AuthCacheServiceLive=m,exports.AuthContextService=N,exports.AuthContextServiceLive=P,exports.BadRequestError=y,exports.NoAuthCacheServiceLive=h,exports.NoAuthContextServiceLive=F,exports.NotFoundError=v,exports.ValidationError=_,exports.createErrorResponseBody=b,exports.createFlowServerLayer=M,exports.createGenericErrorResponseBody=S,exports.createUploadServerLayer=j,exports.createUploadistaErrorResponseBody=x,exports.extractFlowAndStorageId=A,exports.extractJobAndNodeId=k,exports.extractJobIdFromStatus=O,exports.getAuthCredentials=c.t,exports.getLastSegment=w,exports.getRouteSegments=E,exports.handleFlowError=D,exports.hasBasePath=T,exports.parseUrlSegments=C;
1
+ const e=require(`./auth-B3XCQncE.cjs`);let t=require(`effect`),n=require(`@uploadista/core/flow`),r=require(`@uploadista/core/types`),i=require(`@uploadista/core/utils`),a=require(`@uploadista/event-broadcaster-memory`),o=require(`@uploadista/event-emitter-websocket`),s=require(`@uploadista/observability`),c=require(`@uploadista/core/upload`),l=require(`@uploadista/core/errors`);var u=class extends t.Context.Tag(`AuthCacheService`)(){};const d=(e={})=>{let n=e.maxSize??1e4,r=e.ttl??36e5,i=new Map,a=()=>{let e=Date.now();for(let[t,n]of i.entries())e-n.timestamp>r&&i.delete(t)},o=()=>{if(i.size<=n)return;let e=null,t=1/0;for(let[n,r]of i.entries())r.timestamp<t&&(t=r.timestamp,e=n);e&&i.delete(e)};return t.Layer.succeed(u,{set:(e,n)=>t.Effect.sync(()=>{i.size%100==0&&a(),i.set(e,{authContext:n,timestamp:Date.now()}),o()}),get:e=>t.Effect.sync(()=>{let t=i.get(e);return t?Date.now()-t.timestamp>r?(i.delete(e),null):t.authContext:null}),delete:e=>t.Effect.sync(()=>{i.delete(e)}),clear:()=>t.Effect.sync(()=>{i.clear()}),size:()=>t.Effect.sync(()=>i.size)})},f=t.Layer.succeed(u,{set:()=>t.Effect.void,get:()=>t.Effect.succeed(null),delete:()=>t.Effect.void,clear:()=>t.Effect.void,size:()=>t.Effect.succeed(0)}),p=e=>e.split(`/`).filter(Boolean),m=e=>{let t=p(e);return t[t.length-1]},h=(e,t)=>e.includes(`${t}/api/`),g=(e,t)=>e.replace(`${t}/api/`,``).split(`/`).filter(Boolean),_=e=>{let t=500,n=`UNKNOWN_ERROR`,r=`Internal server error`,i;if(typeof e==`object`&&e){let a=e;if(`code`in a&&typeof a.code==`string`&&(n=a.code),`message`in a&&typeof a.message==`string`?r=a.message:`body`in a&&typeof a.body==`string`&&(r=a.body),`details`in a&&(i=a.details),`status`in a&&typeof a.status==`number`)t=a.status;else if(`code`in a)switch(a.code){case`FILE_NOT_FOUND`:case`FLOW_JOB_NOT_FOUND`:case`UPLOAD_ID_NOT_FOUND`:t=404;break;case`FLOW_JOB_ERROR`:case`VALIDATION_ERROR`:case`INVALID_METADATA`:case`INVALID_LENGTH`:case`ABORTED`:case`INVALID_TERMINATION`:t=400;break;case`INVALID_OFFSET`:t=409;break;case`ERR_SIZE_EXCEEDED`:case`ERR_MAX_SIZE_EXCEEDED`:t=413;break;case`FILE_NO_LONGER_EXISTS`:t=410;break;case`MISSING_OFFSET`:case`INVALID_CONTENT_TYPE`:t=403;break;default:t=500}`message`in a&&a.message===`Invalid JSON body`&&(t=400,n=`VALIDATION_ERROR`)}let a={status:t,code:n,message:r};return i!==void 0&&(a.details=i),a},v=e=>e[e.length-2],y=e=>({jobId:e[e.length-3],nodeId:e[e.length-1]}),b=e=>({storageId:e.pop(),flowId:e.pop()}),x=({kvStore:e,eventEmitter:n,dataStore:i,bufferedDataStore:a,generateId:o})=>{let s=t.Layer.provide(r.uploadFileKvStore,e),l=t.Layer.provide(i,s),u=a?t.Layer.provide(a,s):t.Layer.empty,d=t.Layer.provide(r.uploadEventEmitter,n),f=t.Layer.mergeAll(l,s,d,...o?[o]:[],u);return t.Layer.provide(c.uploadServer,f)},S=({kvStore:e,eventEmitter:i,flowProvider:a,uploadServer:o})=>{let s=t.Layer.provide(r.flowJobKvStore,e),c=t.Layer.provide(r.flowEventEmitter,i),l=t.Layer.mergeAll(a,c,s,o);return t.Layer.provide(n.flowServer,l)};var C=class extends t.Context.Tag(`AuthContextService`)(){};const w=e=>t.Layer.succeed(C,{getClientId:()=>t.Effect.succeed(e?.clientId??null),getMetadata:()=>t.Effect.succeed(e?.metadata??{}),hasPermission:n=>t.Effect.succeed(e?.permissions?.includes(n)??!1),getAuthContext:()=>t.Effect.succeed(e)}),T=w(null),E=({flowId:e})=>t.Effect.gen(function*(){let r=yield*n.FlowServer,i=yield*(yield*C).getClientId();return i&&(yield*t.Effect.logInfo(`[Flow] Getting flow data: ${e}, client: ${i}`)),{status:200,body:yield*r.getFlowData(e,i)}}),D=({flowId:e,storageId:r,inputs:i})=>t.Effect.gen(function*(){let a=yield*n.FlowServer,o=yield*C,s=yield*u,c=yield*o.getClientId();c?(yield*t.Effect.logInfo(`[Flow] Executing flow: ${e}, storage: ${r}, client: ${c}`),yield*t.Effect.logInfo(JSON.stringify(i,null,2))):(yield*t.Effect.logInfo(`[Flow] Executing flow: ${e}, storage: ${r}`),yield*t.Effect.logInfo(`[Flow] Inputs: ${JSON.stringify(i,null,2)}`)),yield*t.Effect.logInfo(`[Flow] Calling flowServer.runFlow...`);let l=yield*a.runFlow({flowId:e,storageId:r,clientId:c,inputs:i}).pipe(t.Effect.tap(()=>t.Effect.logInfo(`[Flow] runFlow completed successfully`)),t.Effect.tapError(e=>t.Effect.logError(`[Flow] runFlow failed with error: ${e}`))),d=yield*o.getAuthContext();return d&&(yield*s.set(l.id,d)),yield*t.Effect.logInfo(`[Flow] Flow started with jobId: ${l.id}`),{status:200,body:l}}),O=({jobId:e})=>t.Effect.gen(function*(){let r=yield*n.FlowServer,i=yield*C,a=yield*u,o=yield*i.getClientId();if(!e)throw Error(`No job id`);o&&(yield*t.Effect.logInfo(`[Flow] Getting job status: ${e}, client: ${o}`));let s=yield*r.getJobStatus(e);return(s.status===`completed`||s.status===`failed`)&&(yield*a.delete(e),o&&(yield*t.Effect.logInfo(`[Flow] Flow ${s.status}, cleared auth cache: ${e}`))),{status:200,body:s}}),k=({jobId:e,nodeId:r,newData:i})=>t.Effect.gen(function*(){let a=yield*n.FlowServer,o=yield*C,s=yield*u,c=yield*o.getClientId();if(c||=(yield*s.get(e))?.clientId??null,c&&(yield*t.Effect.logInfo(`[Flow] Continuing flow: jobId=${e}, nodeId=${r}, client: ${c}`)),i===void 0)throw Error(`Missing newData`);let l=yield*a.resumeFlow({jobId:e,nodeId:r,newData:i,clientId:c});return(l.status===`completed`||l.status===`failed`)&&(yield*s.delete(e),c&&(yield*t.Effect.logInfo(`[Flow] Flow ${l.status}, cleared auth cache: ${e}`))),{status:200,body:l}}),A=({jobId:e})=>t.Effect.gen(function*(){let r=yield*n.FlowServer,i=yield*C,a=yield*u,o=yield*i.getClientId();o||=(yield*a.get(e))?.clientId??null,o&&(yield*t.Effect.logInfo(`[Flow] Pausing flow: jobId=${e}, client: ${o}`));let s=yield*r.pauseFlow(e,o);return o&&(yield*t.Effect.logInfo(`[Flow] Flow paused: ${e}, status: ${s.status}`)),{status:200,body:s}}),j=({jobId:e})=>t.Effect.gen(function*(){let r=yield*n.FlowServer,i=yield*C,a=yield*u;if(!e)throw Error(`No job id`);let o=yield*i.getClientId();o||=(yield*a.get(e))?.clientId??null,o&&(yield*t.Effect.logInfo(`[Flow] Cancelling flow: jobId=${e}, client: ${o}`));let s=yield*r.cancelFlow(e,o);return yield*a.delete(e),o&&(yield*t.Effect.logInfo(`[Flow] Flow cancelled, cleared auth cache: ${e}`)),{status:200,body:s}});var M=class extends Error{constructor(e,t=500,n=`INTERNAL_ERROR`){super(e),this.statusCode=t,this.errorCode=n,this.name=`AdapterError`}},N=class extends M{constructor(e){super(e,400,`VALIDATION_ERROR`),this.name=`ValidationError`}},P=class extends M{constructor(e){super(`${e} not found`,404,`NOT_FOUND`),this.name=`NotFoundError`}},F=class extends M{constructor(e){super(e,400,`BAD_REQUEST`),this.name=`BadRequestError`}};const I=e=>({error:e.message,code:e.errorCode,timestamp:new Date().toISOString()}),L=e=>{let t={error:e.body,code:e.code,timestamp:new Date().toISOString()};return e.details!==void 0&&(t.details=e.details),t},R=(e=`Internal server error`)=>({error:e,code:`INTERNAL_ERROR`,timestamp:new Date().toISOString()}),z=e=>t.Effect.gen(function*(){let n=yield*c.UploadServer,a=yield*C,o=yield*u,s=yield*a.getClientId();s&&(yield*t.Effect.logInfo(`[Upload] Creating upload for client: ${s}`));let l=yield*t.Effect.sync(()=>r.inputFileSchema.safeParse(e.data));if(!l.success)return yield*t.Effect.fail(new N(`Invalid input file schema`));if(l.data.checksumAlgorithm&&!(0,i.isSupportedAlgorithm)(l.data.checksumAlgorithm))return yield*t.Effect.fail(new N(`Unsupported checksum algorithm: ${l.data.checksumAlgorithm}. Supported algorithms: sha256`));let d=yield*n.createUpload(l.data,s),f=yield*a.getAuthContext();return f&&(yield*o.set(d.id,f)),s&&(yield*t.Effect.logInfo(`[Upload] Upload created: ${d.id} for client: ${s}`)),{status:200,body:d}}),B=({storageId:e})=>t.Effect.gen(function*(){let t=yield*c.UploadServer,n=yield*(yield*C).getClientId();return{status:200,body:{storageId:e,capabilities:yield*t.getCapabilities(e,n),timestamp:new Date().toISOString()}}}),V=({uploadId:e})=>t.Effect.gen(function*(){return{status:200,body:yield*(yield*c.UploadServer).getUpload(e)}}),H=e=>t.Effect.gen(function*(){let n=yield*c.UploadServer,r=yield*C,i=yield*u,a=yield*s.MetricsService,{uploadId:o,data:l}=e,d=yield*r.getClientId(),f=yield*r.getMetadata();if(!d){let e=yield*i.get(o);d=e?.clientId??null,f=e?.metadata??{}}d&&(yield*t.Effect.logInfo(`[Upload] Uploading chunk for upload: ${o}, client: ${d}`));let p=yield*n.uploadChunk(o,d,l);return p.size&&p.offset>=p.size&&(yield*i.delete(o),d&&(yield*t.Effect.logInfo(`[Upload] Upload completed, cleared auth cache: ${o}`)),d&&p.size?(yield*t.Effect.logInfo(`[Upload] Recording metrics for org: ${d}, size: ${p.size}`),yield*t.Effect.forkDaemon(a.recordUpload(d,p.size,f))):yield*t.Effect.logWarning(`[Upload] Cannot record metrics - missing organizationId or size`)),d&&(yield*t.Effect.logInfo(`[Upload] Chunk uploaded for upload: ${o}, client: ${d}`)),{status:200,body:p}}),U=e=>t.Effect.gen(function*(){switch(e.type){case`create-upload`:return yield*z(e);case`get-capabilities`:return yield*B(e);case`get-upload`:return yield*V(e);case`upload-chunk`:return yield*H(e);case`get-flow`:return yield*E(e);case`run-flow`:return yield*D(e);case`job-status`:return yield*O(e);case`resume-flow`:return yield*k(e);case`pause-flow`:return yield*A(e);case`cancel-flow`:return yield*j(e);case`not-found`:return{status:404,headers:{"Content-Type":`application/json`},body:{error:`Not found`}};case`bad-request`:return{status:400,body:{error:`Bad request`,message:e.message}};case`method-not-allowed`:return{status:405,headers:{"Content-Type":`application/json`},body:{error:`Method not allowed`}};case`unsupported-content-type`:return{status:415,headers:{"Content-Type":`application/json`},body:{error:`Unsupported content type`}}}}),W=async({flows:e,dataStore:c,kvStore:l,plugins:u=[],eventEmitter:f,eventBroadcaster:p=a.memoryEventBroadcaster,withTracing:m=!1,baseUrl:h=`uploadista`,generateId:g=i.GenerateIdLive,metricsLayer:v,bufferedDataStore:y,adapter:b,authCacheConfig:C})=>{let T=f??(0,o.webSocketEventEmitter)(p),E=h.endsWith(`/`)?h.slice(0,-1):h,D=t.Layer.effect(n.FlowProvider,t.Effect.succeed({getFlow:(t,n)=>e(t,n)}));if(!T)throw Error(`eventEmitter is required. Provide an event emitter layer in the configuration.`);let O=x({kvStore:l,eventEmitter:T,dataStore:await(0,r.createDataStoreLayer)(c),bufferedDataStore:y,generateId:g}),k=S({kvStore:l,eventEmitter:T,flowProvider:D,uploadServer:O}),A=d(C),j=v??s.NoOpMetricsServiceLive,M=t.Layer.mergeAll(O,k,j,A,...u),N=t.ManagedRuntime.make(M);return{handler:async e=>{let r=t.Effect.gen(function*(){let r=yield*b.extractRequest(e,{baseUrl:E}),i=null;if(b.runAuthMiddleware){let n=yield*b.runAuthMiddleware(e).pipe(t.Effect.timeout(`5 seconds`),t.Effect.catchAll(()=>(console.error(`Auth middleware timeout exceeded (5 seconds)`),t.Effect.succeed({_tag:`TimeoutError`}))),t.Effect.catchAllCause(e=>(console.error(`Auth middleware error:`,e),t.Effect.succeed({_tag:`AuthError`,error:e}))));if(n&&typeof n==`object`&&`_tag`in n&&n._tag===`TimeoutError`)return yield*b.sendResponse({status:503,headers:{"Content-Type":`application/json`},body:{error:`Authentication service unavailable`,message:`Authentication took too long to respond. Please try again.`}},e);if(n&&typeof n==`object`&&`_tag`in n&&n._tag===`AuthError`)return yield*b.sendResponse({status:500,headers:{"Content-Type":`application/json`},body:{error:`Internal Server Error`,message:`An error occurred during authentication`}},e);if(n===null)return yield*b.sendResponse({status:401,headers:{"Content-Type":`application/json`},body:{error:`Unauthorized`,message:`Invalid credentials`}},e);i=n}let a=w(i),o=[];if(b.extractWaitUntil){let r=b.extractWaitUntil(e);r&&o.push(t.Layer.succeed(n.FlowWaitUntil,r))}let s=t.Layer.mergeAll(a,A,j,...u,...o);if(r.type===`not-found`)return yield*b.sendResponse({type:`not-found`,status:404,headers:{"Content-Type":`application/json`},body:{error:`Not found`}},e);let c=yield*U(r).pipe(t.Effect.provide(s));return yield*b.sendResponse(c,e)}).pipe(t.Effect.catchAll(t=>{let n=_(t),r={code:n.code,message:n.message};n.details!==void 0&&(r.details=n.details);let i={status:n.status,headers:{"Content-Type":`application/json`},body:r};return b.sendResponse(i,e)}));return m?N.runPromise(r.pipe(t.Effect.provide(s.NodeSdkLive))):N.runPromise(r)},websocketHandler:await N.runPromise(b.webSocketHandler({baseUrl:E})),baseUrl:E,dispose:()=>N.dispose()}},G=(e,n,r)=>t.Effect.gen(function*(){if(!n){yield*t.Effect.sync(()=>{r.send(JSON.stringify({type:`error`,message:`Job ID is required for flow event subscription`,code:`MISSING_JOB_ID`}))});return}yield*e.subscribeToFlowEvents(n,r)}),K=(e,n)=>t.Effect.gen(function*(){n&&(yield*e.unsubscribeFromFlowEvents(n))}),q=(e,n,r)=>t.Effect.gen(function*(){if(!n){yield*t.Effect.sync(()=>{r.send(JSON.stringify({type:`error`,message:`Upload ID is required for upload event subscription`,code:`MISSING_UPLOAD_ID`}))});return}yield*e.subscribeToUploadEvents(n,r)}),J=(e,n)=>t.Effect.gen(function*(){n&&(yield*e.unsubscribeFromUploadEvents(n))}),Y=(e,n,r)=>{let{connection:i,isFlowRoute:a,isUploadRoute:o,jobId:s,uploadId:c,eventId:u}=e;return t.Effect.gen(function*(){a&&(yield*G(r,s,i)),o&&(yield*q(n,c,i)),i.send(JSON.stringify({type:`connection`,message:`Uploadista WebSocket connected`,id:u,jobId:s,uploadId:c,timestamp:new Date().toISOString()}))}).pipe(t.Effect.catchAll(e=>t.Effect.sync(()=>{console.error(`Error subscribing to events:`,e);let t=e instanceof l.UploadistaError?e.body:`Failed to subscribe to events`;i.send(JSON.stringify({type:`error`,message:t,code:e instanceof l.UploadistaError?e.code:`SUBSCRIPTION_ERROR`}))})))},X=(e,n)=>t.Effect.sync(()=>{try{JSON.parse(e).type===`ping`&&n.send(JSON.stringify({type:`pong`,timestamp:new Date().toISOString()}))}catch(e){console.error(`Error handling WebSocket message:`,e),n.send(JSON.stringify({type:`error`,message:`Invalid message format`}))}}),Z=(e,n,r)=>{let{isFlowRoute:i,isUploadRoute:a,jobId:o,uploadId:s}=e;return t.Effect.gen(function*(){i&&(yield*K(r,o)),a&&(yield*J(n,s))}).pipe(t.Effect.catchAll(e=>t.Effect.sync(()=>{console.error(`Error unsubscribing from events:`,e instanceof l.UploadistaError?e.body:e)})))},Q=(e,n)=>t.Effect.sync(()=>{console.error(`WebSocket error for event ${n}:`,e)});exports.AdapterError=M,exports.AuthCacheService=u,exports.AuthCacheServiceLive=d,exports.AuthContextService=C,exports.AuthContextServiceLive=w,exports.BadRequestError=F,exports.NoAuthCacheServiceLive=f,exports.NoAuthContextServiceLive=T,exports.NotFoundError=P,exports.ValidationError=N,exports.createErrorResponseBody=I,exports.createFlowServerLayer=S,exports.createGenericErrorResponseBody=R,exports.createUploadServerLayer=x,exports.createUploadistaErrorResponseBody=L,exports.createUploadistaServer=W,exports.extractFlowAndStorageId=b,exports.extractJobAndNodeId=y,exports.extractJobIdFromStatus=v,exports.getAuthCredentials=e.t,exports.getLastSegment=m,exports.getRouteSegments=g,exports.handleFlowError=_,exports.handleWebSocketClose=Z,exports.handleWebSocketError=Q,exports.handleWebSocketMessage=X,exports.handleWebSocketOpen=Y,exports.hasBasePath=h,exports.parseUrlSegments=p;