@niledatabase/express 5.0.0-alpha.9 → 5.0.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.d.mts +7 -27
- package/dist/index.d.ts +7 -27
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -3
- package/CHANGELOG.md +0 -32
- package/jest.config.js +0 -6
- package/src/express.test.ts +0 -54
- package/src/index.ts +0 -146
- package/tsup.config.js +0 -9
package/dist/index.d.mts
CHANGED
|
@@ -1,31 +1,11 @@
|
|
|
1
|
-
import { Server,
|
|
1
|
+
import { Server, ExtensionState } from '@niledatabase/server';
|
|
2
|
+
import { Express, Request, Response, NextFunction } from 'express';
|
|
2
3
|
|
|
3
4
|
declare function cleaner(val: string): string;
|
|
4
|
-
declare
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
put: string[];
|
|
9
|
-
delete: string[];
|
|
10
|
-
};
|
|
5
|
+
declare const express: (app?: Express) => (instance: Server) => {
|
|
6
|
+
id: string;
|
|
7
|
+
onConfigure: () => void;
|
|
8
|
+
onHandleRequest: (params: [Request, Response, NextFunction]) => Promise<void | ExtensionState.onHandleRequest>;
|
|
11
9
|
};
|
|
12
|
-
type HandlerConfig = {
|
|
13
|
-
muteResponse?: boolean;
|
|
14
|
-
init?: RequestInit;
|
|
15
|
-
};
|
|
16
|
-
declare function NileExpressHandler(nile: Server, config?: HandlerConfig & NileConfig): Promise<{
|
|
17
|
-
handler: (req: any, res?: any) => Promise<{
|
|
18
|
-
body: string;
|
|
19
|
-
status: number;
|
|
20
|
-
headers: Record<string, string | string[]>;
|
|
21
|
-
response: Response;
|
|
22
|
-
} | null | undefined>;
|
|
23
|
-
paths: {
|
|
24
|
-
get: string[];
|
|
25
|
-
post: string[];
|
|
26
|
-
put: string[];
|
|
27
|
-
delete: string[];
|
|
28
|
-
};
|
|
29
|
-
}>;
|
|
30
10
|
|
|
31
|
-
export {
|
|
11
|
+
export { cleaner, express };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,31 +1,11 @@
|
|
|
1
|
-
import { Server,
|
|
1
|
+
import { Server, ExtensionState } from '@niledatabase/server';
|
|
2
|
+
import { Express, Request, Response, NextFunction } from 'express';
|
|
2
3
|
|
|
3
4
|
declare function cleaner(val: string): string;
|
|
4
|
-
declare
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
put: string[];
|
|
9
|
-
delete: string[];
|
|
10
|
-
};
|
|
5
|
+
declare const express: (app?: Express) => (instance: Server) => {
|
|
6
|
+
id: string;
|
|
7
|
+
onConfigure: () => void;
|
|
8
|
+
onHandleRequest: (params: [Request, Response, NextFunction]) => Promise<void | ExtensionState.onHandleRequest>;
|
|
11
9
|
};
|
|
12
|
-
type HandlerConfig = {
|
|
13
|
-
muteResponse?: boolean;
|
|
14
|
-
init?: RequestInit;
|
|
15
|
-
};
|
|
16
|
-
declare function NileExpressHandler(nile: Server, config?: HandlerConfig & NileConfig): Promise<{
|
|
17
|
-
handler: (req: any, res?: any) => Promise<{
|
|
18
|
-
body: string;
|
|
19
|
-
status: number;
|
|
20
|
-
headers: Record<string, string | string[]>;
|
|
21
|
-
response: Response;
|
|
22
|
-
} | null | undefined>;
|
|
23
|
-
paths: {
|
|
24
|
-
get: string[];
|
|
25
|
-
post: string[];
|
|
26
|
-
put: string[];
|
|
27
|
-
delete: string[];
|
|
28
|
-
};
|
|
29
|
-
}>;
|
|
30
10
|
|
|
31
|
-
export {
|
|
11
|
+
export { cleaner, express };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var m=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var U=(s,t)=>{for(var n in t)m(s,n,{get:t[n],enumerable:!0})},b=(s,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of O(t))!C.call(s,o)&&o!==n&&m(s,o,{get:()=>t[o],enumerable:!(i=I(t,o))||i.enumerable});return s};var L=s=>b(m({},"__esModule",{value:!0}),s);var $={};U($,{cleaner:()=>x,express:()=>A});module.exports=L($);var S=require("async_hooks"),T=require("@niledatabase/server");function x(s){return s.replaceAll(/\{([^}]+)\}/g,":$1")}var w=new S.AsyncLocalStorage,A=s=>{let t=!1;return n=>{let{error:i,debug:o}=n.logger("[EXTENSION][express]"),y=e=>{w.getStore()?.set("context",e),n.withContext(e)};function q(e){s&&(o("routes configured"),s.get(e.paths.get,e.handlers.GET),s.post(e.paths.post,e.handlers.POST),s.put(e.paths.put,e.handlers.PUT),s.delete(e.paths.delete,e.handlers.DELETE))}return!t&&s&&(o("initializing express extension with middleware"),s.use((e,r,a)=>{w.run(new Map,()=>a())}),s.param("tenantId",(e,r,a,h)=>{o(`tenantId param set: ${h}`),y({tenantId:h,headers:new Headers(H(e.headers))}),a()}),s.use((e,r,a)=>{y({headers:new Headers(H(e.headers))}),a()})),t=!0,{id:"express",onConfigure:()=>{let{paths:e}=n,r={get:e.get.map(x),post:e.post.map(x),put:e.put.map(x),delete:e.delete.map(x)};o(`paths configured ${JSON.stringify(r)}`),n.paths=r,q(n)},onHandleRequest:async e=>{let[r,a,h]=e;o("handling response");let f=r.protocol+"://"+r.get("host")+r.originalUrl;try{new URL(f)}catch{throw new Error("Invalid URL \u2014 are you running Express?")}let E=r.method,g={method:E,headers:new Headers};r.headers?.cookie&&g.headers.set("cookie",r.headers.cookie),["POST","PUT"].includes(E)&&r.body&&(g.body=JSON.stringify(r.body));let P=new Request(f,g);o(`[${E}] proxy: ${f} ${JSON.stringify(g)}`);let p,N={headers:new Headers(r.headers),tenantId:r.params?.tenantId||void 0};try{p=await n.withContext(N,async d=>await d.handlers[E](P,{disableExtensions:["express"]}))}catch(d){return i(d),h()}let u;try{u=await p.clone().json()}catch{u=await p.text()}let c={};return p.headers.forEach((d,l)=>{if(!["content-length","transfer-encoding"].includes(l.toLowerCase()))if(c[l]){let R=c[l];c[l]=Array.isArray(R)?[...R,d]:[R,d]}else c[l]=d}),a.headersSent||(o("sending response"),a.status(p.status).set(c),typeof u=="string"?a.send(u):a.json(u??{})),T.ExtensionState.onHandleRequest}}}};function H(s){let t={};for(let[n,i]of Object.entries(s))typeof i=="string"?t[n]=i:Array.isArray(i)&&(t[n]=i.join(","));return t}0&&(module.exports={cleaner,express});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'async_hooks';\nimport { IncomingHttpHeaders } from 'http';\n\nimport { PartialContext, ExtensionState, Server } from '@niledatabase/server';\nimport type {\n Request as ExpressRequest,\n Response as ExpressResponse,\n NextFunction,\n Express,\n} from 'express';\n\nexport function cleaner(val: string) {\n return val.replaceAll(/\\{([^}]+)\\}/g, ':$1');\n}\n\ntype ExpressRouteHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void | Promise<void>;\n\ntype ExpressRouteFunctions = {\n GET: ExpressRouteHandler;\n POST: ExpressRouteHandler;\n PUT: ExpressRouteHandler;\n DELETE: ExpressRouteHandler;\n};\n\ntype NileWithExpress = Server & {\n handlers: ExpressRouteFunctions;\n};\n\n// AsyncLocalStorage to persist context per request\nconst contextStore = new AsyncLocalStorage<Map<string, unknown>>();\n\n// Express extension factory\nexport const express = (app?: Express) => {\n let init = false;\n\n return (instance: Server) => {\n const { error, debug } = instance.logger('[EXTENSION][express]');\n\n // Internal context helpers - I think we delete this now?\n const setRequestContext = (context: PartialContext) => {\n contextStore.getStore()?.set('context', context);\n\n instance.withContext(context);\n };\n\n function doConfigure(server: NileWithExpress) {\n if (app) {\n debug('routes configured');\n app.get(server.paths.get, server.handlers.GET);\n app.post(server.paths.post, server.handlers.POST);\n app.put(server.paths.put, server.handlers.PUT);\n app.delete(server.paths.delete, server.handlers.DELETE);\n }\n }\n\n if (!init && app) {\n debug('initializing express extension with middleware');\n\n app.use((req, res, next) => {\n contextStore.run(new Map(), () => next());\n });\n\n app.param('tenantId', (req, res, next, tenantId) => {\n debug(`tenantId param set: ${tenantId}`);\n setRequestContext({\n tenantId,\n headers: new Headers(normalizeHeaders(req.headers)),\n });\n next();\n });\n\n app.use((req, res, next) => {\n setRequestContext({\n headers: new Headers(normalizeHeaders(req.headers)),\n });\n next();\n });\n }\n\n init = true;\n\n return {\n id: 'express',\n\n onConfigure: () => {\n const { paths: rawPaths } = instance;\n const paths = {\n get: rawPaths.get.map(cleaner),\n post: rawPaths.post.map(cleaner),\n put: rawPaths.put.map(cleaner),\n delete: rawPaths.delete.map(cleaner),\n };\n debug(`paths configured ${JSON.stringify(paths)}`);\n instance.paths = paths;\n doConfigure(instance as NileWithExpress);\n },\n\n onHandleRequest: async (\n params: [ExpressRequest, ExpressResponse, NextFunction]\n ) => {\n const [req, res, next] = params;\n debug('handling response');\n\n const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;\n\n try {\n new URL(reqUrl);\n } catch {\n throw new Error('Invalid URL — are you running Express?');\n }\n\n const method = req.method;\n const init: RequestInit = { method, headers: new Headers() };\n\n if (req.headers?.cookie) {\n (init.headers as Headers).set('cookie', req.headers.cookie);\n }\n\n if (['POST', 'PUT'].includes(method) && req.body) {\n init.body = JSON.stringify(req.body);\n }\n\n const proxyRequest = new Request(reqUrl, init);\n debug(`[${method}] proxy: ${reqUrl} ${JSON.stringify(init)}`);\n\n let response: Response;\n const context = {\n headers: new Headers(req.headers as HeadersInit),\n tenantId: req.params?.tenantId || undefined,\n };\n try {\n response = await instance.withContext(context, async (ctx) => {\n return (await ctx.handlers[\n method as 'GET' | 'POST' | 'PUT' | 'DELETE'\n ](proxyRequest, { disableExtensions: ['express'] })) as Response;\n });\n } catch (e) {\n error(e);\n return next();\n }\n\n let body;\n try {\n body = await response.clone().json();\n } catch {\n body = await response.text();\n }\n\n const newHeaders: Record<string, string | string[]> = {};\n response.headers.forEach((value, key) => {\n if (\n !['content-length', 'transfer-encoding'].includes(key.toLowerCase())\n ) {\n if (newHeaders[key]) {\n const prev = newHeaders[key];\n newHeaders[key] = Array.isArray(prev)\n ? [...prev, value]\n : [prev, value];\n } else {\n newHeaders[key] = value;\n }\n }\n });\n if (!res.headersSent) {\n debug('sending response');\n res.status(response.status).set(newHeaders);\n typeof body === 'string' ? res.send(body) : res.json(body ?? {});\n }\n\n return ExtensionState.onHandleRequest;\n },\n };\n };\n};\n\nfunction normalizeHeaders(headers: IncomingHttpHeaders): HeadersInit {\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === 'string') {\n normalized[key] = value;\n } else if (Array.isArray(value)) {\n normalized[key] = value.join(','); // Join multi-values with commas\n }\n }\n return normalized;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,IAAA,eAAAC,EAAAJ,GAAA,IAAAK,EAAkC,uBAGlCC,EAAuD,gCAQhD,SAASJ,EAAQK,EAAa,CACnC,OAAOA,EAAI,WAAW,eAAgB,KAAK,CAC7C,CAoBA,IAAMC,EAAe,IAAI,oBAGZL,EAAWM,GAAkB,CACxC,IAAIC,EAAO,GAEX,OAAQC,GAAqB,CAC3B,GAAM,CAAE,MAAAC,EAAO,MAAAC,CAAM,EAAIF,EAAS,OAAO,sBAAsB,EAGzDG,EAAqBC,GAA4B,CACrDP,EAAa,SAAS,GAAG,IAAI,UAAWO,CAAO,EAE/CJ,EAAS,YAAYI,CAAO,CAC9B,EAEA,SAASC,EAAYC,EAAyB,CACxCR,IACFI,EAAM,mBAAmB,EACzBJ,EAAI,IAAIQ,EAAO,MAAM,IAAKA,EAAO,SAAS,GAAG,EAC7CR,EAAI,KAAKQ,EAAO,MAAM,KAAMA,EAAO,SAAS,IAAI,EAChDR,EAAI,IAAIQ,EAAO,MAAM,IAAKA,EAAO,SAAS,GAAG,EAC7CR,EAAI,OAAOQ,EAAO,MAAM,OAAQA,EAAO,SAAS,MAAM,EAE1D,CAEA,MAAI,CAACP,GAAQD,IACXI,EAAM,gDAAgD,EAEtDJ,EAAI,IAAI,CAACS,EAAKC,EAAKC,IAAS,CAC1BZ,EAAa,IAAI,IAAI,IAAO,IAAMY,EAAK,CAAC,CAC1C,CAAC,EAEDX,EAAI,MAAM,WAAY,CAACS,EAAKC,EAAKC,EAAMC,IAAa,CAClDR,EAAM,uBAAuBQ,CAAQ,EAAE,EACvCP,EAAkB,CAChB,SAAAO,EACA,QAAS,IAAI,QAAQC,EAAiBJ,EAAI,OAAO,CAAC,CACpD,CAAC,EACDE,EAAK,CACP,CAAC,EAEDX,EAAI,IAAI,CAACS,EAAKC,EAAKC,IAAS,CAC1BN,EAAkB,CAChB,QAAS,IAAI,QAAQQ,EAAiBJ,EAAI,OAAO,CAAC,CACpD,CAAC,EACDE,EAAK,CACP,CAAC,GAGHV,EAAO,GAEA,CACL,GAAI,UAEJ,YAAa,IAAM,CACjB,GAAM,CAAE,MAAOa,CAAS,EAAIZ,EACtBa,EAAQ,CACZ,IAAKD,EAAS,IAAI,IAAIrB,CAAO,EAC7B,KAAMqB,EAAS,KAAK,IAAIrB,CAAO,EAC/B,IAAKqB,EAAS,IAAI,IAAIrB,CAAO,EAC7B,OAAQqB,EAAS,OAAO,IAAIrB,CAAO,CACrC,EACAW,EAAM,oBAAoB,KAAK,UAAUW,CAAK,CAAC,EAAE,EACjDb,EAAS,MAAQa,EACjBR,EAAYL,CAA2B,CACzC,EAEA,gBAAiB,MACfc,GACG,CACH,GAAM,CAACP,EAAKC,EAAKC,CAAI,EAAIK,EACzBZ,EAAM,mBAAmB,EAEzB,IAAMa,EAASR,EAAI,SAAW,MAAQA,EAAI,IAAI,MAAM,EAAIA,EAAI,YAE5D,GAAI,CACF,IAAI,IAAIQ,CAAM,CAChB,MAAQ,CACN,MAAM,IAAI,MAAM,6CAAwC,CAC1D,CAEA,IAAMC,EAAST,EAAI,OACbR,EAAoB,CAAE,OAAAiB,EAAQ,QAAS,IAAI,OAAU,EAEvDT,EAAI,SAAS,QACdR,EAAK,QAAoB,IAAI,SAAUQ,EAAI,QAAQ,MAAM,EAGxD,CAAC,OAAQ,KAAK,EAAE,SAASS,CAAM,GAAKT,EAAI,OAC1CR,EAAK,KAAO,KAAK,UAAUQ,EAAI,IAAI,GAGrC,IAAMU,EAAe,IAAI,QAAQF,EAAQhB,CAAI,EAC7CG,EAAM,IAAIc,CAAM,YAAYD,CAAM,IAAI,KAAK,UAAUhB,CAAI,CAAC,EAAE,EAE5D,IAAImB,EACEd,EAAU,CACd,QAAS,IAAI,QAAQG,EAAI,OAAsB,EAC/C,SAAUA,EAAI,QAAQ,UAAY,MACpC,EACA,GAAI,CACFW,EAAW,MAAMlB,EAAS,YAAYI,EAAS,MAAOe,GAC5C,MAAMA,EAAI,SAChBH,CACF,EAAEC,EAAc,CAAE,kBAAmB,CAAC,SAAS,CAAE,CAAC,CACnD,CACH,OAASG,EAAG,CACV,OAAAnB,EAAMmB,CAAC,EACAX,EAAK,CACd,CAEA,IAAIY,EACJ,GAAI,CACFA,EAAO,MAAMH,EAAS,MAAM,EAAE,KAAK,CACrC,MAAQ,CACNG,EAAO,MAAMH,EAAS,KAAK,CAC7B,CAEA,IAAMI,EAAgD,CAAC,EACvD,OAAAJ,EAAS,QAAQ,QAAQ,CAACK,EAAOC,IAAQ,CACvC,GACE,CAAC,CAAC,iBAAkB,mBAAmB,EAAE,SAASA,EAAI,YAAY,CAAC,EAEnE,GAAIF,EAAWE,CAAG,EAAG,CACnB,IAAMC,EAAOH,EAAWE,CAAG,EAC3BF,EAAWE,CAAG,EAAI,MAAM,QAAQC,CAAI,EAChC,CAAC,GAAGA,EAAMF,CAAK,EACf,CAACE,EAAMF,CAAK,CAClB,MACED,EAAWE,CAAG,EAAID,CAGxB,CAAC,EACIf,EAAI,cACPN,EAAM,kBAAkB,EACxBM,EAAI,OAAOU,EAAS,MAAM,EAAE,IAAII,CAAU,EAC1C,OAAOD,GAAS,SAAWb,EAAI,KAAKa,CAAI,EAAIb,EAAI,KAAKa,GAAQ,CAAC,CAAC,GAG1D,iBAAe,eACxB,CACF,CACF,CACF,EAEA,SAASV,EAAiBe,EAA2C,CACnE,IAAMC,EAAqC,CAAC,EAC5C,OAAW,CAACH,EAAKD,CAAK,IAAK,OAAO,QAAQG,CAAO,EAC3C,OAAOH,GAAU,SACnBI,EAAWH,CAAG,EAAID,EACT,MAAM,QAAQA,CAAK,IAC5BI,EAAWH,CAAG,EAAID,EAAM,KAAK,GAAG,GAGpC,OAAOI,CACT","names":["index_exports","__export","cleaner","express","__toCommonJS","import_async_hooks","import_server","val","contextStore","app","init","instance","error","debug","setRequestContext","context","doConfigure","server","req","res","next","tenantId","normalizeHeaders","rawPaths","paths","params","reqUrl","method","proxyRequest","response","ctx","e","body","newHeaders","value","key","prev","headers","normalized"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function
|
|
1
|
+
import{AsyncLocalStorage as q}from"async_hooks";import{ExtensionState as P}from"@niledatabase/server";function g(t){return t.replaceAll(/\{([^}]+)\}/g,":$1")}var y=new q,U=t=>{let i=!1;return n=>{let{error:d,debug:o}=n.logger("[EXTENSION][express]"),m=e=>{y.getStore()?.set("context",e),n.withContext(e)};function H(e){t&&(o("routes configured"),t.get(e.paths.get,e.handlers.GET),t.post(e.paths.post,e.handlers.POST),t.put(e.paths.put,e.handlers.PUT),t.delete(e.paths.delete,e.handlers.DELETE))}return!i&&t&&(o("initializing express extension with middleware"),t.use((e,s,r)=>{y.run(new Map,()=>r())}),t.param("tenantId",(e,s,r,x)=>{o(`tenantId param set: ${x}`),m({tenantId:x,headers:new Headers(w(e.headers))}),r()}),t.use((e,s,r)=>{m({headers:new Headers(w(e.headers))}),r()})),i=!0,{id:"express",onConfigure:()=>{let{paths:e}=n,s={get:e.get.map(g),post:e.post.map(g),put:e.put.map(g),delete:e.delete.map(g)};o(`paths configured ${JSON.stringify(s)}`),n.paths=s,H(n)},onHandleRequest:async e=>{let[s,r,x]=e;o("handling response");let f=s.protocol+"://"+s.get("host")+s.originalUrl;try{new URL(f)}catch{throw new Error("Invalid URL \u2014 are you running Express?")}let h=s.method,E={method:h,headers:new Headers};s.headers?.cookie&&E.headers.set("cookie",s.headers.cookie),["POST","PUT"].includes(h)&&s.body&&(E.body=JSON.stringify(s.body));let S=new Request(f,E);o(`[${h}] proxy: ${f} ${JSON.stringify(E)}`);let p,T={headers:new Headers(s.headers),tenantId:s.params?.tenantId||void 0};try{p=await n.withContext(T,async a=>await a.handlers[h](S,{disableExtensions:["express"]}))}catch(a){return d(a),x()}let u;try{u=await p.clone().json()}catch{u=await p.text()}let c={};return p.headers.forEach((a,l)=>{if(!["content-length","transfer-encoding"].includes(l.toLowerCase()))if(c[l]){let R=c[l];c[l]=Array.isArray(R)?[...R,a]:[R,a]}else c[l]=a}),r.headersSent||(o("sending response"),r.status(p.status).set(c),typeof u=="string"?r.send(u):r.json(u??{})),P.onHandleRequest}}}};function w(t){let i={};for(let[n,d]of Object.entries(t))typeof d=="string"?i[n]=d:Array.isArray(d)&&(i[n]=d.join(","));return i}export{g as cleaner,U as express};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'async_hooks';\nimport { IncomingHttpHeaders } from 'http';\n\nimport { PartialContext, ExtensionState, Server } from '@niledatabase/server';\nimport type {\n Request as ExpressRequest,\n Response as ExpressResponse,\n NextFunction,\n Express,\n} from 'express';\n\nexport function cleaner(val: string) {\n return val.replaceAll(/\\{([^}]+)\\}/g, ':$1');\n}\n\ntype ExpressRouteHandler = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n) => void | Promise<void>;\n\ntype ExpressRouteFunctions = {\n GET: ExpressRouteHandler;\n POST: ExpressRouteHandler;\n PUT: ExpressRouteHandler;\n DELETE: ExpressRouteHandler;\n};\n\ntype NileWithExpress = Server & {\n handlers: ExpressRouteFunctions;\n};\n\n// AsyncLocalStorage to persist context per request\nconst contextStore = new AsyncLocalStorage<Map<string, unknown>>();\n\n// Express extension factory\nexport const express = (app?: Express) => {\n let init = false;\n\n return (instance: Server) => {\n const { error, debug } = instance.logger('[EXTENSION][express]');\n\n // Internal context helpers - I think we delete this now?\n const setRequestContext = (context: PartialContext) => {\n contextStore.getStore()?.set('context', context);\n\n instance.withContext(context);\n };\n\n function doConfigure(server: NileWithExpress) {\n if (app) {\n debug('routes configured');\n app.get(server.paths.get, server.handlers.GET);\n app.post(server.paths.post, server.handlers.POST);\n app.put(server.paths.put, server.handlers.PUT);\n app.delete(server.paths.delete, server.handlers.DELETE);\n }\n }\n\n if (!init && app) {\n debug('initializing express extension with middleware');\n\n app.use((req, res, next) => {\n contextStore.run(new Map(), () => next());\n });\n\n app.param('tenantId', (req, res, next, tenantId) => {\n debug(`tenantId param set: ${tenantId}`);\n setRequestContext({\n tenantId,\n headers: new Headers(normalizeHeaders(req.headers)),\n });\n next();\n });\n\n app.use((req, res, next) => {\n setRequestContext({\n headers: new Headers(normalizeHeaders(req.headers)),\n });\n next();\n });\n }\n\n init = true;\n\n return {\n id: 'express',\n\n onConfigure: () => {\n const { paths: rawPaths } = instance;\n const paths = {\n get: rawPaths.get.map(cleaner),\n post: rawPaths.post.map(cleaner),\n put: rawPaths.put.map(cleaner),\n delete: rawPaths.delete.map(cleaner),\n };\n debug(`paths configured ${JSON.stringify(paths)}`);\n instance.paths = paths;\n doConfigure(instance as NileWithExpress);\n },\n\n onHandleRequest: async (\n params: [ExpressRequest, ExpressResponse, NextFunction]\n ) => {\n const [req, res, next] = params;\n debug('handling response');\n\n const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;\n\n try {\n new URL(reqUrl);\n } catch {\n throw new Error('Invalid URL — are you running Express?');\n }\n\n const method = req.method;\n const init: RequestInit = { method, headers: new Headers() };\n\n if (req.headers?.cookie) {\n (init.headers as Headers).set('cookie', req.headers.cookie);\n }\n\n if (['POST', 'PUT'].includes(method) && req.body) {\n init.body = JSON.stringify(req.body);\n }\n\n const proxyRequest = new Request(reqUrl, init);\n debug(`[${method}] proxy: ${reqUrl} ${JSON.stringify(init)}`);\n\n let response: Response;\n const context = {\n headers: new Headers(req.headers as HeadersInit),\n tenantId: req.params?.tenantId || undefined,\n };\n try {\n response = await instance.withContext(context, async (ctx) => {\n return (await ctx.handlers[\n method as 'GET' | 'POST' | 'PUT' | 'DELETE'\n ](proxyRequest, { disableExtensions: ['express'] })) as Response;\n });\n } catch (e) {\n error(e);\n return next();\n }\n\n let body;\n try {\n body = await response.clone().json();\n } catch {\n body = await response.text();\n }\n\n const newHeaders: Record<string, string | string[]> = {};\n response.headers.forEach((value, key) => {\n if (\n !['content-length', 'transfer-encoding'].includes(key.toLowerCase())\n ) {\n if (newHeaders[key]) {\n const prev = newHeaders[key];\n newHeaders[key] = Array.isArray(prev)\n ? [...prev, value]\n : [prev, value];\n } else {\n newHeaders[key] = value;\n }\n }\n });\n if (!res.headersSent) {\n debug('sending response');\n res.status(response.status).set(newHeaders);\n typeof body === 'string' ? res.send(body) : res.json(body ?? {});\n }\n\n return ExtensionState.onHandleRequest;\n },\n };\n };\n};\n\nfunction normalizeHeaders(headers: IncomingHttpHeaders): HeadersInit {\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === 'string') {\n normalized[key] = value;\n } else if (Array.isArray(value)) {\n normalized[key] = value.join(','); // Join multi-values with commas\n }\n }\n return normalized;\n}\n"],"mappings":"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","names":["AsyncLocalStorage","ExtensionState","cleaner","val","contextStore","express","app","init","instance","error","debug","setRequestContext","context","doConfigure","server","req","res","next","tenantId","normalizeHeaders","rawPaths","paths","params","reqUrl","method","proxyRequest","response","ctx","e","body","newHeaders","value","key","prev","headers","normalized"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@niledatabase/express",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"singleQuote": true,
|
|
18
18
|
"trailingComma": "es5"
|
|
19
19
|
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
20
23
|
"scripts": {
|
|
21
24
|
"build": "tsup src/index.ts",
|
|
22
25
|
"test": "jest"
|
|
@@ -31,12 +34,15 @@
|
|
|
31
34
|
"access": "public"
|
|
32
35
|
},
|
|
33
36
|
"peerDependencies": {
|
|
34
|
-
"@niledatabase/server": "
|
|
37
|
+
"@niledatabase/server": ">=5.0.0-alpha",
|
|
38
|
+
"express": "^5.0.0 || ^4.0.0"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
41
|
+
"@types/express": "^5",
|
|
42
|
+
"express": "^5.1.0",
|
|
37
43
|
"jest": "^29.7.0",
|
|
38
44
|
"ts-jest": "^29.3.4",
|
|
39
45
|
"tsup": "^8.5.0"
|
|
40
46
|
},
|
|
41
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "bc6ee6499ed130cb605ea2a373e0054072ea8fb0"
|
|
42
48
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
# [5.0.0-alpha.9](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.8...v5.0.0-alpha.9) (2025-06-16)
|
|
7
|
-
|
|
8
|
-
**Note:** Version bump only for package @niledatabase/express
|
|
9
|
-
|
|
10
|
-
# [5.0.0-alpha.8](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.7...v5.0.0-alpha.8) (2025-06-12)
|
|
11
|
-
|
|
12
|
-
**Note:** Version bump only for package @niledatabase/express
|
|
13
|
-
|
|
14
|
-
# [5.0.0-alpha.7](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.6...v5.0.0-alpha.7) (2025-06-11)
|
|
15
|
-
|
|
16
|
-
**Note:** Version bump only for package @niledatabase/express
|
|
17
|
-
|
|
18
|
-
# [5.0.0-alpha.6](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.5...v5.0.0-alpha.6) (2025-06-11)
|
|
19
|
-
|
|
20
|
-
### Bug Fixes
|
|
21
|
-
|
|
22
|
-
- **server:** move logging to the config object ([6e3e380](https://github.com/niledatabase/nile-js/commit/6e3e38014f5b9795552af0a7b97e2d3fe6cd1a88))
|
|
23
|
-
|
|
24
|
-
# [5.0.0-alpha.5](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.4...v5.0.0-alpha.5) (2025-06-10)
|
|
25
|
-
|
|
26
|
-
**Note:** Version bump only for package @niledatabase/express
|
|
27
|
-
|
|
28
|
-
# [5.0.0-alpha.4](https://github.com/niledatabase/nile-js/compare/v5.0.0-alpha.3...v5.0.0-alpha.4) (2025-06-10)
|
|
29
|
-
|
|
30
|
-
### Features
|
|
31
|
-
|
|
32
|
-
- **server:** invites ([c10f598](https://github.com/niledatabase/nile-js/commit/c10f5980bcbc55ed436ce8cceca4111aa8e6a276))
|
package/jest.config.js
DELETED
package/src/express.test.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Server } from '@niledatabase/server';
|
|
2
|
-
|
|
3
|
-
import { expressPaths } from '.';
|
|
4
|
-
|
|
5
|
-
describe('express', () => {
|
|
6
|
-
it('cleans express paths', () => {
|
|
7
|
-
const nile = new Server({
|
|
8
|
-
apiUrl: 'http://localhost:3000',
|
|
9
|
-
user: '123',
|
|
10
|
-
password: '123',
|
|
11
|
-
databaseName: '123',
|
|
12
|
-
});
|
|
13
|
-
const { paths } = expressPaths(nile);
|
|
14
|
-
expect(Object.keys(paths)).toEqual(['get', 'post', 'put', 'delete']);
|
|
15
|
-
expect(paths.delete).toEqual([
|
|
16
|
-
'/api/tenants/:tenantId/users/:userId',
|
|
17
|
-
'/api/tenants/:tenantId',
|
|
18
|
-
]);
|
|
19
|
-
expect(paths.post).toEqual([
|
|
20
|
-
'/api/tenants/:tenantId/users',
|
|
21
|
-
'/api/signup',
|
|
22
|
-
'/api/users',
|
|
23
|
-
'/api/tenants',
|
|
24
|
-
'/api/auth/session',
|
|
25
|
-
'/api/auth/signin/:provider',
|
|
26
|
-
'/api/auth/reset-password',
|
|
27
|
-
'/api/auth/providers',
|
|
28
|
-
'/api/auth/csrf',
|
|
29
|
-
'/api/auth/callback/:provider',
|
|
30
|
-
'/api/auth/signout',
|
|
31
|
-
]);
|
|
32
|
-
expect(paths.put).toEqual([
|
|
33
|
-
'/api/tenants/:tenantId/users',
|
|
34
|
-
'/api/users',
|
|
35
|
-
'/api/tenants/:tenantId',
|
|
36
|
-
'/api/auth/reset-password',
|
|
37
|
-
]);
|
|
38
|
-
expect(paths.get).toEqual([
|
|
39
|
-
'/api/me',
|
|
40
|
-
'/api/tenants/:tenantId/users',
|
|
41
|
-
'/api/tenants',
|
|
42
|
-
'/api/tenants/:tenantId',
|
|
43
|
-
'/api/auth/session',
|
|
44
|
-
'/api/auth/signin',
|
|
45
|
-
'/api/auth/providers',
|
|
46
|
-
'/api/auth/csrf',
|
|
47
|
-
'/api/auth/reset-password',
|
|
48
|
-
'/api/auth/callback',
|
|
49
|
-
'/api/auth/signout',
|
|
50
|
-
'/api/auth/verify-request',
|
|
51
|
-
'/api/auth/error',
|
|
52
|
-
]);
|
|
53
|
-
});
|
|
54
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { NileConfig, Server } from '@niledatabase/server';
|
|
2
|
-
|
|
3
|
-
export function cleaner(val: string) {
|
|
4
|
-
return val.replaceAll(/\{([^}]+)\}/g, ':$1');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function expressPaths(nile: Server) {
|
|
8
|
-
const nilePaths = nile.getPaths();
|
|
9
|
-
const paths = {
|
|
10
|
-
get: nilePaths.get.map(cleaner),
|
|
11
|
-
post: nilePaths.post.map(cleaner),
|
|
12
|
-
put: nilePaths.put.map(cleaner),
|
|
13
|
-
delete: nilePaths.delete.map(cleaner),
|
|
14
|
-
};
|
|
15
|
-
return {
|
|
16
|
-
paths,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type HandlerConfig = { muteResponse?: boolean; init?: RequestInit };
|
|
21
|
-
export async function NileExpressHandler(
|
|
22
|
-
nile: Server,
|
|
23
|
-
config?: HandlerConfig & NileConfig
|
|
24
|
-
) {
|
|
25
|
-
const error = config?.logger ? config?.logger('express').error : () => null;
|
|
26
|
-
async function handler(
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
-
req: any,
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
res?: any
|
|
31
|
-
): Promise<
|
|
32
|
-
| {
|
|
33
|
-
body: string;
|
|
34
|
-
status: number;
|
|
35
|
-
headers: Record<string, string | string[]>;
|
|
36
|
-
response: Response;
|
|
37
|
-
}
|
|
38
|
-
| null
|
|
39
|
-
| undefined
|
|
40
|
-
> {
|
|
41
|
-
const headers = new Headers();
|
|
42
|
-
if (!req || typeof req !== 'object') {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
if (!('url' in req) || typeof req?.url !== 'string') {
|
|
46
|
-
error('A url is necessary for the nile express handler');
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
const method =
|
|
50
|
-
'method' in req && typeof req.method === 'string' ? req.method : 'GET';
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
'headers' in req &&
|
|
54
|
-
typeof req.headers === 'object' &&
|
|
55
|
-
req.headers &&
|
|
56
|
-
'cookie' in req.headers &&
|
|
57
|
-
typeof req.headers.cookie === 'string'
|
|
58
|
-
) {
|
|
59
|
-
headers.set('cookie', req.headers.cookie);
|
|
60
|
-
}
|
|
61
|
-
const _init: RequestInit = { method, ...config?.init };
|
|
62
|
-
|
|
63
|
-
if ('body' in req) {
|
|
64
|
-
if (method === 'POST' || method === 'PUT') {
|
|
65
|
-
headers.set('content-type', 'application/json');
|
|
66
|
-
_init.body = JSON.stringify(req.body);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
_init.headers = headers;
|
|
71
|
-
|
|
72
|
-
const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
|
|
73
|
-
|
|
74
|
-
// be sure its a valid url
|
|
75
|
-
try {
|
|
76
|
-
new URL(reqUrl);
|
|
77
|
-
} catch (e) {
|
|
78
|
-
error('Invalid URL', {
|
|
79
|
-
url: reqUrl,
|
|
80
|
-
error: e,
|
|
81
|
-
});
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
const proxyRequest = new Request(reqUrl, _init);
|
|
85
|
-
let response;
|
|
86
|
-
try {
|
|
87
|
-
response = await nile.handlers[
|
|
88
|
-
method as 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
89
|
-
](proxyRequest);
|
|
90
|
-
} catch (e) {
|
|
91
|
-
error(e);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let body;
|
|
95
|
-
|
|
96
|
-
if (response instanceof Response) {
|
|
97
|
-
try {
|
|
98
|
-
const tryJson = await response.clone();
|
|
99
|
-
body = await tryJson.json();
|
|
100
|
-
} catch (e) {
|
|
101
|
-
body = await response.text();
|
|
102
|
-
}
|
|
103
|
-
const newHeaders: Record<string, string | string[]> = {};
|
|
104
|
-
response.headers.forEach((value, key) => {
|
|
105
|
-
if (
|
|
106
|
-
!['content-length', 'transfer-encoding'].includes(key.toLowerCase())
|
|
107
|
-
) {
|
|
108
|
-
if (newHeaders[key]) {
|
|
109
|
-
const prev = newHeaders[key];
|
|
110
|
-
if (Array.isArray(prev)) {
|
|
111
|
-
newHeaders[key] = [...prev, value];
|
|
112
|
-
} else {
|
|
113
|
-
newHeaders[key] = [prev, value];
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
newHeaders[key] = value;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (config?.muteResponse !== true) {
|
|
122
|
-
if (res) {
|
|
123
|
-
res.status(response.status).set(newHeaders);
|
|
124
|
-
if (typeof body === 'string') {
|
|
125
|
-
res.send(body);
|
|
126
|
-
} else {
|
|
127
|
-
res.json(body ?? {});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
body,
|
|
135
|
-
status: response.status,
|
|
136
|
-
headers: newHeaders,
|
|
137
|
-
response,
|
|
138
|
-
};
|
|
139
|
-
} else {
|
|
140
|
-
error('Bad response', { response });
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const { paths } = expressPaths(nile);
|
|
145
|
-
return { handler, paths };
|
|
146
|
-
}
|