@uploadista/adapters-express 0.1.3 → 0.2.0
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.cjs +1 -1
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let e=require(`effect`),t=require(`@uploadista/core`),n=require(`@uploadista/server`);const r=async e=>{if(e.body&&typeof e.body==`object`)return e.body;let t=[];for await(let n of e)t.push(n);let n=Buffer.concat(t).toString();return JSON.parse(n)},i=(t,{baseUrl:n})=>e.Effect.promise(async()=>{let e=new URL(t.request.url,`http://${t.request.get(`host`)}`),i=t.request.get(`Accept`),a=`/${n}/`;if(e.pathname.startsWith(a)&&t.request.method===`GET`){let t=e.pathname.slice(a.length);if(t===`health`||t===`healthz`)return{type:`health`,acceptHeader:i};if(t===`ready`||t===`readyz`)return{type:`health-ready`,acceptHeader:i};if(t===`health/components`)return{type:`health-components`,acceptHeader:i}}let o=`/${n}/api/`;if(!e.pathname.includes(o))return{type:`not-found`};let s=e.pathname.replace(`${n}/api/`,``).split(`/`).filter(Boolean);if(s[0]===`upload`||s.includes(`upload`))switch(t.request.method){case`POST`:return{type:`create-upload`,data:await r(t.request)};case`GET`:if(s[s.length-1]===`capabilities`){let t=e.searchParams.get(`storageId`),n=s[s.length-2],r=t||(n===`upload`?null:n);return r?{type:`get-capabilities`,storageId:r}:{type:`bad-request`,message:`Storage ID is required`}}return s.length<2?{type:`bad-request`,message:`Upload ID is required`}:{type:`get-upload`,uploadId:s[1]};case`PATCH`:{if(s.length<2)return{type:`bad-request`,message:`Upload ID is required`};let e=new ReadableStream({start(e){t.request.on(`data`,t=>{e.enqueue(t)}),t.request.on(`end`,()=>{e.close()}),t.request.on(`error`,t=>{e.error(t)})}});return{type:`upload-chunk`,uploadId:s[1],data:e}}default:return{type:`method-not-allowed`}}else if(s[0]===`flow`||s.includes(`flow`))switch(t.request.method){case`GET`:return{type:`get-flow`,flowId:s[1]};case`POST`:{let e=await r(t.request);return!e||typeof e!=`object`||!(`inputs`in e)?{type:`bad-request`,message:`Inputs are required`}:{type:`run-flow`,flowId:s[1],storageId:s[2],inputs:e.inputs}}default:return{type:`method-not-allowed`}}else if(s[0]===`dlq`||s.includes(`dlq`))switch(t.request.method){case`GET`:return s.length===1?{type:`dlq-list`,options:{status:e.searchParams.get(`status`),flowId:e.searchParams.get(`flowId`),clientId:e.searchParams.get(`clientId`),limit:e.searchParams.get(`limit`)?Number.parseInt(e.searchParams.get(`limit`),10):void 0,offset:e.searchParams.get(`offset`)?Number.parseInt(e.searchParams.get(`offset`),10):void 0}}:s[1]===`stats`?{type:`dlq-stats`}:{type:`dlq-get`,itemId:s[1]};case`POST`:return s[1]===`cleanup`?{type:`dlq-cleanup`,options:await r(t.request).catch(()=>({}))}:s[1]===`retry-all`?{type:`dlq-retry-all`,options:await r(t.request).catch(()=>({}))}:s[2]===`retry`?{type:`dlq-retry`,itemId:s[1]}:s[2]===`resolve`?{type:`dlq-resolve`,itemId:s[1]}:{type:`method-not-allowed`};case`DELETE`:return s.length<2?{type:`bad-request`,message:`Item ID is required`}:{type:`dlq-delete`,itemId:s[1]};default:return{type:`method-not-allowed`}}else if(s[0]===`jobs`||s.includes(`jobs`)){if(t.request.method===`GET`&&e.pathname.endsWith(`/status`))return s.length<3?{type:`bad-request`,message:`Job ID is required`}:{type:`job-status`,jobId:s[1]};if(t.request.method===`PATCH`&&s.includes(`resume`)){let e=s[1];if(!e)return{type:`bad-request`,message:`Job ID is required`};let n=s[3];if(!n)return{type:`bad-request`,message:`Node ID is required`};let i=t.request.get(`content-type`),a;if(i?.includes(`application/octet-stream`))a=t.request;else if(i?.includes(`application/json`)){let e=await r(t.request);if(!e||typeof e!=`object`||!(`newData`in e))return{type:`bad-request`,message:`Missing newData`};a=e.newData}else return{type:`unsupported-content-type`};return{type:`resume-flow`,jobId:e,nodeId:n,newData:a}}else if(t.request.method===`POST`&&e.pathname.endsWith(`/pause`))return{type:`pause-flow`,jobId:s[1]};else if(t.request.method===`POST`&&e.pathname.endsWith(`/cancel`))return{type:`cancel-flow`,jobId:s[1]};return{type:`method-not-allowed`}}else return{type:`not-found`}}),a=(t,n)=>e.Effect.sync(()=>{let e=t.headers||{};e[`Content-Type`]||=`application/json`;for(let[t,r]of Object.entries(e))n.response.set(t,r);return n.response.status(t.status).send(t.body)});function o(e,t){let n=RegExp(`[?&]${t}=([^&]*)`),r=e.match(n);return r?.[1]?decodeURIComponent(r[1]):void 0}const s=new Map,c=(e,t)=>{let n=new URL(e.url||``,`http://${e.headers.host}`),r=`${t}/ws/`;if(!n.pathname.includes(r))return{type:`invalid-path`,expectedPrefix:r};let i=n.pathname.replace(r,``).split(`/`).filter(Boolean),a=i.includes(`upload`),s=i.includes(`flow`),c=o(e.url||``,`jobId`),l=o(e.url||``,`uploadId`);if(!c&&!l&&i.length>=2){let e=i[0],t=i[1];e===`flow`?c=t:e===`upload`&&(l=t)}let u=c||l;return{baseUrl:t,pathname:n.pathname,routeSegments:i,isUploadRoute:a,isFlowRoute:s,jobId:c,uploadId:l,eventId:u,connection:null}},l=async(e,t)=>{try{let n=new URL(e.url||``,`http://${e.headers.host}`).searchParams.get(`token`),r=null;if(r=n?await t({request:{...e,header:t=>t.toLowerCase()===`authorization`?`Bearer ${n}`:e.headers[t.toLowerCase()]},response:{}}):await t({request:e,response:{}}),!r){let e=n?`token`:`cookies`;return{success:!1,error:{message:`Authentication failed: invalid or expired ${e}`,code:4001,authMethod:e}}}return console.log(`WebSocket authenticated for user: ${r.clientId}`),{success:!0,authResult:r}}catch(e){return console.error(`WebSocket auth error:`,e),{success:!1,error:{message:`Authentication error`,code:4001,authMethod:`unknown`}}}},u=(r,i)=>e.Effect.gen(function*(){let a=yield*t.UploadEngine,o=yield*t.FlowEngine;return(t,u)=>{let d=c(u,r);if(console.log(`🔍 WebSocket request details:`,d),`type`in d&&d.type===`invalid-path`){t.send(JSON.stringify({type:`invalid-path`,message:`WebSocket path must start with ${d.expectedPrefix}`,expectedPrefix:d.expectedPrefix})),t.close(1e3,`Invalid path`);return}let f=d,p={id:`conn_${Date.now()}_${Math.random().toString(36).substring(2,11)}`,send:e=>{t.readyState===t.OPEN?(console.log(`📤 Sending WebSocket message to connection ${p.id}:`,e.substring(0,100)),t.send(e)):console.warn(`⚠️ Cannot send message, WebSocket not open. State: ${t.readyState}`)},close:(e,n)=>t.close(e,n),get readyState(){return t.readyState}};f.connection=p,(async()=>{if(i){let e=await l(u,i);if(!e.success){t.send(JSON.stringify({type:`auth-failed`,message:e.error?.message,code:`AUTH_FAILED`,authMethod:e.error?.authMethod})),t.close(e.error?.code||4001,e.error?.message);return}e.authResult&&s.set(p.id,e.authResult)}console.log(`🔍 WebSocket open for eventId:`,f.eventId,`with connection id:`,p.id);let r=(0,n.handleWebSocketOpen)(f,a,o);e.Effect.runFork(r)})(),t.on(`message`,t=>{let r=(0,n.handleWebSocketMessage)(t,p);e.Effect.runFork(r)}),t.on(`close`,()=>{f.connection?.id&&(s.delete(f.connection.id),console.log(`Cleared auth cache for WebSocket connection: ${f.connection.id}`));let t=(0,n.handleWebSocketClose)(f,a,o);e.Effect.runFork(t)}),t.on(`error`,(...t)=>{let r=t[0],i=(0,n.handleWebSocketError)(r,f.eventId);e.Effect.runFork(i)})}}),d=(t={})=>{let{authMiddleware:n}=t;return{extractRequest:i,sendResponse:a,webSocketHandler:({baseUrl:e})=>u(e,n),runAuthMiddleware:n?t=>e.Effect.tryPromise(()=>n(t)).pipe(e.Effect.catchAll(t=>(console.error(`Express auth middleware failed:`,t),e.Effect.succeed(null)))):void 0}};exports.expressAdapter=d;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`effect`),t=require(`@uploadista/core`),n=require(`@uploadista/server`);const r=async e=>{if(e.body&&typeof e.body==`object`)return e.body;let t=[];for await(let n of e)t.push(n);let n=Buffer.concat(t).toString();return JSON.parse(n)},i=(t,{baseUrl:n})=>e.Effect.promise(async()=>{let e=new URL(t.request.url,`http://${t.request.get(`host`)}`),i=t.request.get(`Accept`),a=`/${n}/`;if(e.pathname.startsWith(a)&&t.request.method===`GET`){let t=e.pathname.slice(a.length);if(t===`health`||t===`healthz`)return{type:`health`,acceptHeader:i};if(t===`ready`||t===`readyz`)return{type:`health-ready`,acceptHeader:i};if(t===`health/components`)return{type:`health-components`,acceptHeader:i}}let o=`/${n}/api/`;if(!e.pathname.includes(o))return{type:`not-found`};let s=e.pathname.replace(`${n}/api/`,``).split(`/`).filter(Boolean);if(s[0]===`upload`||s.includes(`upload`))switch(t.request.method){case`POST`:return{type:`create-upload`,data:await r(t.request)};case`GET`:if(s[s.length-1]===`capabilities`){let t=e.searchParams.get(`storageId`),n=s[s.length-2],r=t||(n===`upload`?null:n);return r?{type:`get-capabilities`,storageId:r}:{type:`bad-request`,message:`Storage ID is required`}}return s.length<2?{type:`bad-request`,message:`Upload ID is required`}:{type:`get-upload`,uploadId:s[1]};case`PATCH`:{if(s.length<2)return{type:`bad-request`,message:`Upload ID is required`};let e=new ReadableStream({start(e){t.request.on(`data`,t=>{e.enqueue(t)}),t.request.on(`end`,()=>{e.close()}),t.request.on(`error`,t=>{e.error(t)})}});return{type:`upload-chunk`,uploadId:s[1],data:e}}default:return{type:`method-not-allowed`}}else if(s[0]===`flow`||s.includes(`flow`))switch(t.request.method){case`GET`:return{type:`get-flow`,flowId:s[1]};case`POST`:{let e=await r(t.request);return!e||typeof e!=`object`||!(`inputs`in e)?{type:`bad-request`,message:`Inputs are required`}:{type:`run-flow`,flowId:s[1],storageId:s[2],inputs:e.inputs}}default:return{type:`method-not-allowed`}}else if(s[0]===`dlq`||s.includes(`dlq`))switch(t.request.method){case`GET`:return s.length===1?{type:`dlq-list`,options:{status:e.searchParams.get(`status`),flowId:e.searchParams.get(`flowId`),clientId:e.searchParams.get(`clientId`),limit:e.searchParams.get(`limit`)?Number.parseInt(e.searchParams.get(`limit`),10):void 0,offset:e.searchParams.get(`offset`)?Number.parseInt(e.searchParams.get(`offset`),10):void 0}}:s[1]===`stats`?{type:`dlq-stats`}:{type:`dlq-get`,itemId:s[1]};case`POST`:return s[1]===`cleanup`?{type:`dlq-cleanup`,options:await r(t.request).catch(()=>({}))}:s[1]===`retry-all`?{type:`dlq-retry-all`,options:await r(t.request).catch(()=>({}))}:s[2]===`retry`?{type:`dlq-retry`,itemId:s[1]}:s[2]===`resolve`?{type:`dlq-resolve`,itemId:s[1]}:{type:`method-not-allowed`};case`DELETE`:return s.length<2?{type:`bad-request`,message:`Item ID is required`}:{type:`dlq-delete`,itemId:s[1]};default:return{type:`method-not-allowed`}}else if(s[0]===`jobs`||s.includes(`jobs`)){if(t.request.method===`GET`&&e.pathname.endsWith(`/status`))return s.length<3?{type:`bad-request`,message:`Job ID is required`}:{type:`job-status`,jobId:s[1]};if(t.request.method===`PATCH`&&s.includes(`resume`)){let e=s[1];if(!e)return{type:`bad-request`,message:`Job ID is required`};let n=s[3];if(!n)return{type:`bad-request`,message:`Node ID is required`};let i=t.request.get(`content-type`),a;if(i?.includes(`application/octet-stream`))a=t.request;else if(i?.includes(`application/json`)){let e=await r(t.request);if(!e||typeof e!=`object`||!(`newData`in e))return{type:`bad-request`,message:`Missing newData`};a=e.newData}else return{type:`unsupported-content-type`};return{type:`resume-flow`,jobId:e,nodeId:n,newData:a}}else if(t.request.method===`POST`&&e.pathname.endsWith(`/pause`))return{type:`pause-flow`,jobId:s[1]};else if(t.request.method===`POST`&&e.pathname.endsWith(`/cancel`))return{type:`cancel-flow`,jobId:s[1]};return{type:`method-not-allowed`}}else return{type:`not-found`}}),a=(t,n)=>e.Effect.sync(()=>{let e=t.headers||{};e[`Content-Type`]||=`application/json`;for(let[t,r]of Object.entries(e))n.response.set(t,r);return n.response.status(t.status).send(t.body)});function o(e,t){let n=RegExp(`[?&]${t}=([^&]*)`),r=e.match(n);return r?.[1]?decodeURIComponent(r[1]):void 0}const s=new Map,c=(e,t)=>{let n=new URL(e.url||``,`http://${e.headers.host}`),r=`${t}/ws/`;if(!n.pathname.includes(r))return{type:`invalid-path`,expectedPrefix:r};let i=n.pathname.replace(r,``).split(`/`).filter(Boolean),a=i.includes(`upload`),s=i.includes(`flow`),c=o(e.url||``,`jobId`),l=o(e.url||``,`uploadId`);if(!c&&!l&&i.length>=2){let e=i[0],t=i[1];e===`flow`?c=t:e===`upload`&&(l=t)}let u=c||l;return{baseUrl:t,pathname:n.pathname,routeSegments:i,isUploadRoute:a,isFlowRoute:s,jobId:c,uploadId:l,eventId:u,connection:null}},l=async(e,t)=>{try{let n=new URL(e.url||``,`http://${e.headers.host}`).searchParams.get(`token`),r=null;if(r=n?await t({request:{...e,header:t=>t.toLowerCase()===`authorization`?`Bearer ${n}`:e.headers[t.toLowerCase()]},response:{}}):await t({request:e,response:{}}),!r){let e=n?`token`:`cookies`;return{success:!1,error:{message:`Authentication failed: invalid or expired ${e}`,code:4001,authMethod:e}}}return console.log(`WebSocket authenticated for user: ${r.clientId}`),{success:!0,authResult:r}}catch(e){return console.error(`WebSocket auth error:`,e),{success:!1,error:{message:`Authentication error`,code:4001,authMethod:`unknown`}}}},u=(r,i)=>e.Effect.gen(function*(){let a=yield*t.UploadEngine,o=yield*t.FlowEngine;return(t,u)=>{let d=c(u,r);if(console.log(`🔍 WebSocket request details:`,d),`type`in d&&d.type===`invalid-path`){t.send(JSON.stringify({type:`invalid-path`,message:`WebSocket path must start with ${d.expectedPrefix}`,expectedPrefix:d.expectedPrefix})),t.close(1e3,`Invalid path`);return}let f=d,p={id:`conn_${Date.now()}_${Math.random().toString(36).substring(2,11)}`,send:e=>{t.readyState===t.OPEN?(console.log(`📤 Sending WebSocket message to connection ${p.id}:`,e.substring(0,100)),t.send(e)):console.warn(`⚠️ Cannot send message, WebSocket not open. State: ${t.readyState}`)},close:(e,n)=>t.close(e,n),get readyState(){return t.readyState}};f.connection=p,(async()=>{if(i){let e=await l(u,i);if(!e.success){t.send(JSON.stringify({type:`auth-failed`,message:e.error?.message,code:`AUTH_FAILED`,authMethod:e.error?.authMethod})),t.close(e.error?.code||4001,e.error?.message);return}e.authResult&&s.set(p.id,e.authResult)}console.log(`🔍 WebSocket open for eventId:`,f.eventId,`with connection id:`,p.id);let r=(0,n.handleWebSocketOpen)(f,a,o);e.Effect.runFork(r)})(),t.on(`message`,t=>{let r=(0,n.handleWebSocketMessage)(t,p);e.Effect.runFork(r)}),t.on(`close`,()=>{f.connection?.id&&(s.delete(f.connection.id),console.log(`Cleared auth cache for WebSocket connection: ${f.connection.id}`));let t=(0,n.handleWebSocketClose)(f,a,o);e.Effect.runFork(t)}),t.on(`error`,(...t)=>{let r=t[0],i=(0,n.handleWebSocketError)(r,f.eventId);e.Effect.runFork(i)})}}),d=(t={})=>{let{authMiddleware:n}=t;return{extractRequest:i,sendResponse:a,webSocketHandler:({baseUrl:e})=>u(e,n),runAuthMiddleware:n?t=>e.Effect.tryPromise(()=>n(t)).pipe(e.Effect.catchAll(t=>(console.error(`Express auth middleware failed:`,t),e.Effect.succeed(null)))):void 0}};exports.expressAdapter=d;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/adapters-express",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "Express adapter for Uploadista",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Uploadista",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"ws": "8.19.0",
|
|
18
|
-
"@uploadista/core": "0.
|
|
19
|
-
"@uploadista/
|
|
20
|
-
"@uploadista/
|
|
21
|
-
"@uploadista/event-emitter-websocket": "0.
|
|
22
|
-
"@uploadista/server": "0.
|
|
18
|
+
"@uploadista/core": "0.2.0",
|
|
19
|
+
"@uploadista/observability": "0.2.0",
|
|
20
|
+
"@uploadista/event-broadcaster-memory": "0.2.0",
|
|
21
|
+
"@uploadista/event-emitter-websocket": "0.2.0",
|
|
22
|
+
"@uploadista/server": "0.2.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"effect": "^3.0.0",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"@types/express": "^5.0.0",
|
|
32
32
|
"@types/node": "24.10.9",
|
|
33
33
|
"@types/ws": "8.18.1",
|
|
34
|
-
"effect": "3.19.
|
|
35
|
-
"tsdown": "0.20.
|
|
34
|
+
"effect": "3.19.17",
|
|
35
|
+
"tsdown": "0.20.3",
|
|
36
36
|
"typescript": "5.9.3",
|
|
37
37
|
"vitest": "4.0.18",
|
|
38
38
|
"zod": "4.3.6",
|
|
39
|
-
"@uploadista/typescript-config": "0.
|
|
39
|
+
"@uploadista/typescript-config": "0.2.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc --noEmit && tsdown",
|