@fonderie/adapter-express 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fonderie, Inc.
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,45 @@
1
+ # @fonderie/adapter-express
2
+
3
+ Run Fonderie bricks inside your existing Express app. `bridge()` builds the
4
+ Fonderie context for every request, `adapt()` converts any Fonderie
5
+ middleware into a native Express one, and `mount()` attaches whole modules.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @fonderie/adapter-express
11
+ ```
12
+
13
+ ## Use
14
+
15
+ ```ts
16
+ import { bridge, adapt, requireAuth } from '@fonderie/adapter-express';
17
+ ```
18
+
19
+ Register `bridge(fonderie)` as global middleware first, then use the
20
+ re-exported guards (`requireAuth`, `requireWorkspace`, `requirePermission`,
21
+ `requireFeature`) directly on routes.
22
+
23
+ `expressRequestToWeb` converts Express requests to web-standard `Request`
24
+ objects for the Fonderie pipeline.
25
+
26
+ ## Why this exists
27
+
28
+ You've shipped this plumbing before — auth, teams, billing, messaging —
29
+ and the next project will ask for it again. Fonderie packages it once:
30
+ plain TypeScript modules for
31
+ [`@fonderie/core`](https://github.com/fonderie-js/sdk/tree/main/packages/core),
32
+ PostgreSQL-backed, self-hosted, MIT. No external control plane, no
33
+ per-seat anything. Register the modules you need; skip the ones you don't.
34
+
35
+ **This package owns** the border crossing. It translates Express requests and
36
+ middleware conventions into Fonderie's, so the bricks run inside an app you
37
+ already have instead of demanding a rewrite.
38
+
39
+ Browse the whole set at
40
+ [fonderie-js/sdk](https://github.com/fonderie-js/sdk) · follow
41
+ [@fonderiejs](https://x.com/fonderiejs)
42
+
43
+ ## License
44
+
45
+ MIT © Fonderie, Inc.
package/dist/index.cjs ADDED
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ OPERATIONS: () => import_permissions2.OPERATIONS,
24
+ adapt: () => adapt,
25
+ bridge: () => bridge,
26
+ expressRequestToWeb: () => expressRequestToWeb,
27
+ mount: () => mount,
28
+ requireAuth: () => requireAuth,
29
+ requireFeature: () => requireFeature,
30
+ requirePermission: () => requirePermission,
31
+ webResponseToExpress: () => webResponseToExpress,
32
+ withWorkspace: () => withWorkspace
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+ var import_middlewares = require("@fonderie/core/middlewares");
36
+ var import_workspaces = require("@fonderie/workspaces");
37
+ var import_permissions = require("@fonderie/permissions");
38
+ var import_billing = require("@fonderie/billing");
39
+ var import_permissions2 = require("@fonderie/permissions");
40
+ async function expressRequestToWeb(req) {
41
+ const encrypted = req.socket.encrypted;
42
+ const protocol = encrypted ? "https" : "http";
43
+ const host = req.headers["host"] ?? "localhost";
44
+ const url = `${protocol}://${host}${req.url ?? "/"}`;
45
+ const headers = new Headers();
46
+ for (const [key, value] of Object.entries(req.headers)) {
47
+ if (!value) continue;
48
+ if (Array.isArray(value)) {
49
+ for (const v of value) headers.append(key, v);
50
+ } else {
51
+ headers.set(key, value);
52
+ }
53
+ }
54
+ const method = req.method ?? "GET";
55
+ const hasBody = !["GET", "HEAD", "OPTIONS"].includes(method.toUpperCase());
56
+ const body = hasBody ? await readStream(req) : null;
57
+ return new Request(url, { method, headers, body });
58
+ }
59
+ async function webResponseToExpress(webRes, res) {
60
+ res.statusCode = webRes.status;
61
+ webRes.headers.forEach((value, key) => res.setHeader(key, value));
62
+ res.end(Buffer.from(await webRes.arrayBuffer()));
63
+ }
64
+ function readStream(req) {
65
+ return new Promise((resolve, reject) => {
66
+ const chunks = [];
67
+ req.on("data", (chunk) => chunks.push(chunk));
68
+ req.on("end", () => {
69
+ const buf = Buffer.concat(chunks);
70
+ resolve(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
71
+ });
72
+ req.on("error", reject);
73
+ });
74
+ }
75
+ function bridge(fonderie) {
76
+ return async (req, _res, next) => {
77
+ try {
78
+ const webReq = await expressRequestToWeb(req);
79
+ req._fonterieReq = webReq;
80
+ req._fonderie = await fonderie.buildContext(webReq.clone());
81
+ if (req._fonderie.meta["body"] !== void 0) {
82
+ req.body = req._fonderie.meta["body"];
83
+ }
84
+ next();
85
+ } catch (err) {
86
+ next(err);
87
+ }
88
+ };
89
+ }
90
+ function adapt(middleware) {
91
+ return async (req, res, next) => {
92
+ const ctx = req._fonderie;
93
+ if (!ctx) {
94
+ next(new Error("[fonderie] bridge() must be registered before adapt()"));
95
+ return;
96
+ }
97
+ let continued = false;
98
+ const result = await middleware(ctx, async () => {
99
+ continued = true;
100
+ return new Response();
101
+ });
102
+ if (continued) {
103
+ next();
104
+ } else {
105
+ await webResponseToExpress(result, res);
106
+ }
107
+ };
108
+ }
109
+ var requireAuth = adapt(import_middlewares.requireAuth);
110
+ function withWorkspace(store) {
111
+ return adapt((0, import_workspaces.withWorkspace)(store));
112
+ }
113
+ function requirePermission(operation, permissionKey) {
114
+ return adapt((0, import_permissions.requirePermission)(operation, permissionKey));
115
+ }
116
+ function requireFeature(key) {
117
+ return adapt((0, import_billing.requireFeature)(key));
118
+ }
119
+ function mount(app, fonderie, register) {
120
+ const infraHandler = async (req, res) => {
121
+ const webReq = req._fonterieReq ?? await expressRequestToWeb(req);
122
+ const webRes = await fonderie.handle(webReq);
123
+ await webResponseToExpress(webRes, res);
124
+ };
125
+ app.use(bridge(fonderie));
126
+ if (register) {
127
+ register(app);
128
+ app.use(infraHandler);
129
+ } else {
130
+ let sealed = false;
131
+ const origListen = app.listen.bind(app);
132
+ app.listen = (...args) => {
133
+ if (!sealed) {
134
+ sealed = true;
135
+ app.use(infraHandler);
136
+ }
137
+ app.listen = origListen;
138
+ return origListen(...args);
139
+ };
140
+ }
141
+ return app;
142
+ }
143
+ // Annotate the CommonJS export names for ESM import in node:
144
+ 0 && (module.exports = {
145
+ OPERATIONS,
146
+ adapt,
147
+ bridge,
148
+ expressRequestToWeb,
149
+ mount,
150
+ requireAuth,
151
+ requireFeature,
152
+ requirePermission,
153
+ webResponseToExpress,
154
+ withWorkspace
155
+ });
156
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\n\nimport type { FonderieApp, IFonderieContext, Middleware } from '@fonderie/core';\nimport { requireAuth as _requireAuth } from '@fonderie/core/middlewares';\nimport { withWorkspace as _withWorkspace } from '@fonderie/workspaces';\nimport { requirePermission as _requirePermission } from '@fonderie/permissions';\nimport { requireFeature as _requireFeature } from '@fonderie/billing';\n\nexport { OPERATIONS } from '@fonderie/permissions';\n\nexport type ExpressRequest = IncomingMessage & { body?: unknown; _fonderie?: IFonderieContext };\nexport type ExpressResponse = ServerResponse;\nexport type ExpressNext = (err?: unknown) => void;\n\n// ── Web Standard ↔ Express translation ───────────────────────────\n\nexport async function expressRequestToWeb(req: ExpressRequest): Promise<Request> {\n\tconst encrypted = (req.socket as { encrypted?: boolean }).encrypted;\n\tconst protocol = encrypted ? 'https' : 'http';\n\tconst host = req.headers['host'] ?? 'localhost';\n\tconst url = `${protocol}://${host}${req.url ?? '/'}`;\n\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(req.headers)) {\n\t\tif (!value) continue;\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const v of value) headers.append(key, v);\n\t\t} else {\n\t\t\theaders.set(key, value);\n\t\t}\n\t}\n\n\tconst method = req.method ?? 'GET';\n\tconst hasBody = !['GET', 'HEAD', 'OPTIONS'].includes(method.toUpperCase());\n\tconst body = hasBody ? await readStream(req) : null;\n\n\treturn new Request(url, { method, headers, body });\n}\n\nexport async function webResponseToExpress(webRes: Response, res: ExpressResponse): Promise<void> {\n\tres.statusCode = webRes.status;\n\twebRes.headers.forEach((value, key) => res.setHeader(key, value));\n\tres.end(Buffer.from(await webRes.arrayBuffer()));\n}\n\nfunction readStream(req: IncomingMessage): Promise<ArrayBuffer> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on('data', (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on('end', () => {\n\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t// slice creates a correctly-sized ArrayBuffer (buf.buffer is a shared pool)\n\t\t\tresolve(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer);\n\t\t});\n\t\treq.on('error', reject);\n\t});\n}\n\n// ── bridge ────────────────────────────────────────────────────────\n//\n// Express middleware. Populates req._fonderie with the fonderie context\n// (user, workspace, meta) for all subsequent route handlers.\n// Also forwards the parsed body to req.body.\n//\n// app.use(bridge(fonderie))\n\nexport function bridge(fonderie: FonderieApp) {\n\treturn async (req: ExpressRequest, _res: ExpressResponse, next: ExpressNext) => {\n\t\ttry {\n\t\t\tconst webReq = await expressRequestToWeb(req);\n\t\t\t// Cache so the infra handler in mount() can reuse it without re-reading\n\t\t\t// the body stream (which can only be consumed once).\n\t\t\t(req as any)._fonterieReq = webReq;\n\t\t\treq._fonderie = await fonderie.buildContext(webReq.clone());\n\t\t\tif (req._fonderie.meta['body'] !== undefined) {\n\t\t\t\treq.body = req._fonderie.meta['body'];\n\t\t\t}\n\t\t\tnext();\n\t\t} catch (err) {\n\t\t\tnext(err);\n\t\t}\n\t};\n}\n\n// ── adapt ─────────────────────────────────────────────────────────\n//\n// Low-level escape hatch — wraps any fonderie Middleware into an Express\n// middleware function. Use this for custom fonderie middleware; prefer the\n// named exports below for the built-in fonderie guards.\n\nexport function adapt(middleware: Middleware) {\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tconst ctx = req._fonderie;\n\t\tif (!ctx) {\n\t\t\tnext(new Error('[fonderie] bridge() must be registered before adapt()'));\n\t\t\treturn;\n\t\t}\n\n\t\tlet continued = false;\n\t\tconst result = await middleware(ctx, async () => {\n\t\t\tcontinued = true;\n\t\t\treturn new Response();\n\t\t});\n\n\t\tif (continued) {\n\t\t\tnext();\n\t\t} else {\n\t\t\tawait webResponseToExpress(result, res);\n\t\t}\n\t};\n}\n\n// ── Pre-adapted middleware ────────────────────────────────────────\n//\n// Drop-in replacements for the fonderie middleware functions — no adapt()\n// needed. Import directly from this package instead of from the source\n// packages, and use them as native Express middleware.\n//\n// app.get('/jobs', requireAuth, withWorkspace(store), ...)\n\nexport const requireAuth = adapt(_requireAuth);\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]) {\n\treturn adapt(_withWorkspace(store));\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n) {\n\treturn adapt(_requirePermission(operation, permissionKey));\n}\n\nexport function requireFeature(key: string) {\n\treturn adapt(_requireFeature(key));\n}\n\n// ── mount ─────────────────────────────────────────────────────────\n//\n// Wires up fonderie to an Express app. Returns the same app so you can add\n// routes after mount() and before app.listen() — infra is sealed lazily\n// when app.listen() is first called:\n//\n// const api = mount(app, fonderie)\n// api.use(buildTodoRouter(store))\n// app.listen(port)\n//\n// Alternatively pass a register callback to be explicit about ordering:\n//\n// mount(app, fonderie, (app) => {\n// app.use(buildTodoRouter(store))\n// })\n\ntype ExpressApp = {\n\tuse: (...args: any[]) => any;\n\tall: (path: string, handler: (req: ExpressRequest, res: ExpressResponse) => void) => void;\n\tlisten: (...args: any[]) => any;\n};\n\nexport function mount<T extends ExpressApp>(\n\tapp: T,\n\tfonderie: FonderieApp,\n\tregister?: (app: T) => void,\n): T {\n\tconst infraHandler = async (req: ExpressRequest, res: ExpressResponse) => {\n\t\tconst webReq = (req as any)._fonterieReq as Request ?? await expressRequestToWeb(req);\n\t\tconst webRes = await fonderie.handle(webReq);\n\t\tawait webResponseToExpress(webRes, res);\n\t};\n\n\tapp.use(bridge(fonderie));\n\n\tif (register) {\n\t\tregister(app);\n\t\tapp.use(infraHandler);\n\t} else {\n\t\tlet sealed = false;\n\t\tconst origListen = app.listen.bind(app);\n\t\t(app as ExpressApp).listen = (...args: any[]) => {\n\t\t\tif (!sealed) {\n\t\t\t\tsealed = true;\n\t\t\t\tapp.use(infraHandler);\n\t\t\t}\n\t\t\t(app as ExpressApp).listen = origListen;\n\t\t\treturn origListen(...args);\n\t\t};\n\t}\n\n\treturn app;\n}\n"],"mappings":"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","names":["import_permissions","_requireAuth","_withWorkspace","_requirePermission","_requireFeature"]}
@@ -0,0 +1,28 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { IFonderieContext, Middleware, FonderieApp } from '@fonderie/core';
3
+ import { withWorkspace as withWorkspace$1 } from '@fonderie/workspaces';
4
+ import { requirePermission as requirePermission$1 } from '@fonderie/permissions';
5
+ export { OPERATIONS } from '@fonderie/permissions';
6
+
7
+ type ExpressRequest = IncomingMessage & {
8
+ body?: unknown;
9
+ _fonderie?: IFonderieContext;
10
+ };
11
+ type ExpressResponse = ServerResponse;
12
+ type ExpressNext = (err?: unknown) => void;
13
+ declare function expressRequestToWeb(req: ExpressRequest): Promise<Request>;
14
+ declare function webResponseToExpress(webRes: Response, res: ExpressResponse): Promise<void>;
15
+ declare function bridge(fonderie: FonderieApp): (req: ExpressRequest, _res: ExpressResponse, next: ExpressNext) => Promise<void>;
16
+ declare function adapt(middleware: Middleware): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
17
+ declare const requireAuth: (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
18
+ declare function withWorkspace(store: Parameters<typeof withWorkspace$1>[0]): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
19
+ declare function requirePermission(operation: Parameters<typeof requirePermission$1>[0], permissionKey: Parameters<typeof requirePermission$1>[1]): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
20
+ declare function requireFeature(key: string): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
21
+ type ExpressApp = {
22
+ use: (...args: any[]) => any;
23
+ all: (path: string, handler: (req: ExpressRequest, res: ExpressResponse) => void) => void;
24
+ listen: (...args: any[]) => any;
25
+ };
26
+ declare function mount<T extends ExpressApp>(app: T, fonderie: FonderieApp, register?: (app: T) => void): T;
27
+
28
+ export { type ExpressNext, type ExpressRequest, type ExpressResponse, adapt, bridge, expressRequestToWeb, mount, requireAuth, requireFeature, requirePermission, webResponseToExpress, withWorkspace };
@@ -0,0 +1,28 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { IFonderieContext, Middleware, FonderieApp } from '@fonderie/core';
3
+ import { withWorkspace as withWorkspace$1 } from '@fonderie/workspaces';
4
+ import { requirePermission as requirePermission$1 } from '@fonderie/permissions';
5
+ export { OPERATIONS } from '@fonderie/permissions';
6
+
7
+ type ExpressRequest = IncomingMessage & {
8
+ body?: unknown;
9
+ _fonderie?: IFonderieContext;
10
+ };
11
+ type ExpressResponse = ServerResponse;
12
+ type ExpressNext = (err?: unknown) => void;
13
+ declare function expressRequestToWeb(req: ExpressRequest): Promise<Request>;
14
+ declare function webResponseToExpress(webRes: Response, res: ExpressResponse): Promise<void>;
15
+ declare function bridge(fonderie: FonderieApp): (req: ExpressRequest, _res: ExpressResponse, next: ExpressNext) => Promise<void>;
16
+ declare function adapt(middleware: Middleware): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
17
+ declare const requireAuth: (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
18
+ declare function withWorkspace(store: Parameters<typeof withWorkspace$1>[0]): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
19
+ declare function requirePermission(operation: Parameters<typeof requirePermission$1>[0], permissionKey: Parameters<typeof requirePermission$1>[1]): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
20
+ declare function requireFeature(key: string): (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => Promise<void>;
21
+ type ExpressApp = {
22
+ use: (...args: any[]) => any;
23
+ all: (path: string, handler: (req: ExpressRequest, res: ExpressResponse) => void) => void;
24
+ listen: (...args: any[]) => any;
25
+ };
26
+ declare function mount<T extends ExpressApp>(app: T, fonderie: FonderieApp, register?: (app: T) => void): T;
27
+
28
+ export { type ExpressNext, type ExpressRequest, type ExpressResponse, adapt, bridge, expressRequestToWeb, mount, requireAuth, requireFeature, requirePermission, webResponseToExpress, withWorkspace };
package/dist/index.js ADDED
@@ -0,0 +1,122 @@
1
+ // src/index.ts
2
+ import { requireAuth as _requireAuth } from "@fonderie/core/middlewares";
3
+ import { withWorkspace as _withWorkspace } from "@fonderie/workspaces";
4
+ import { requirePermission as _requirePermission } from "@fonderie/permissions";
5
+ import { requireFeature as _requireFeature } from "@fonderie/billing";
6
+ import { OPERATIONS } from "@fonderie/permissions";
7
+ async function expressRequestToWeb(req) {
8
+ const encrypted = req.socket.encrypted;
9
+ const protocol = encrypted ? "https" : "http";
10
+ const host = req.headers["host"] ?? "localhost";
11
+ const url = `${protocol}://${host}${req.url ?? "/"}`;
12
+ const headers = new Headers();
13
+ for (const [key, value] of Object.entries(req.headers)) {
14
+ if (!value) continue;
15
+ if (Array.isArray(value)) {
16
+ for (const v of value) headers.append(key, v);
17
+ } else {
18
+ headers.set(key, value);
19
+ }
20
+ }
21
+ const method = req.method ?? "GET";
22
+ const hasBody = !["GET", "HEAD", "OPTIONS"].includes(method.toUpperCase());
23
+ const body = hasBody ? await readStream(req) : null;
24
+ return new Request(url, { method, headers, body });
25
+ }
26
+ async function webResponseToExpress(webRes, res) {
27
+ res.statusCode = webRes.status;
28
+ webRes.headers.forEach((value, key) => res.setHeader(key, value));
29
+ res.end(Buffer.from(await webRes.arrayBuffer()));
30
+ }
31
+ function readStream(req) {
32
+ return new Promise((resolve, reject) => {
33
+ const chunks = [];
34
+ req.on("data", (chunk) => chunks.push(chunk));
35
+ req.on("end", () => {
36
+ const buf = Buffer.concat(chunks);
37
+ resolve(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
38
+ });
39
+ req.on("error", reject);
40
+ });
41
+ }
42
+ function bridge(fonderie) {
43
+ return async (req, _res, next) => {
44
+ try {
45
+ const webReq = await expressRequestToWeb(req);
46
+ req._fonterieReq = webReq;
47
+ req._fonderie = await fonderie.buildContext(webReq.clone());
48
+ if (req._fonderie.meta["body"] !== void 0) {
49
+ req.body = req._fonderie.meta["body"];
50
+ }
51
+ next();
52
+ } catch (err) {
53
+ next(err);
54
+ }
55
+ };
56
+ }
57
+ function adapt(middleware) {
58
+ return async (req, res, next) => {
59
+ const ctx = req._fonderie;
60
+ if (!ctx) {
61
+ next(new Error("[fonderie] bridge() must be registered before adapt()"));
62
+ return;
63
+ }
64
+ let continued = false;
65
+ const result = await middleware(ctx, async () => {
66
+ continued = true;
67
+ return new Response();
68
+ });
69
+ if (continued) {
70
+ next();
71
+ } else {
72
+ await webResponseToExpress(result, res);
73
+ }
74
+ };
75
+ }
76
+ var requireAuth = adapt(_requireAuth);
77
+ function withWorkspace(store) {
78
+ return adapt(_withWorkspace(store));
79
+ }
80
+ function requirePermission(operation, permissionKey) {
81
+ return adapt(_requirePermission(operation, permissionKey));
82
+ }
83
+ function requireFeature(key) {
84
+ return adapt(_requireFeature(key));
85
+ }
86
+ function mount(app, fonderie, register) {
87
+ const infraHandler = async (req, res) => {
88
+ const webReq = req._fonterieReq ?? await expressRequestToWeb(req);
89
+ const webRes = await fonderie.handle(webReq);
90
+ await webResponseToExpress(webRes, res);
91
+ };
92
+ app.use(bridge(fonderie));
93
+ if (register) {
94
+ register(app);
95
+ app.use(infraHandler);
96
+ } else {
97
+ let sealed = false;
98
+ const origListen = app.listen.bind(app);
99
+ app.listen = (...args) => {
100
+ if (!sealed) {
101
+ sealed = true;
102
+ app.use(infraHandler);
103
+ }
104
+ app.listen = origListen;
105
+ return origListen(...args);
106
+ };
107
+ }
108
+ return app;
109
+ }
110
+ export {
111
+ OPERATIONS,
112
+ adapt,
113
+ bridge,
114
+ expressRequestToWeb,
115
+ mount,
116
+ requireAuth,
117
+ requireFeature,
118
+ requirePermission,
119
+ webResponseToExpress,
120
+ withWorkspace
121
+ };
122
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\n\nimport type { FonderieApp, IFonderieContext, Middleware } from '@fonderie/core';\nimport { requireAuth as _requireAuth } from '@fonderie/core/middlewares';\nimport { withWorkspace as _withWorkspace } from '@fonderie/workspaces';\nimport { requirePermission as _requirePermission } from '@fonderie/permissions';\nimport { requireFeature as _requireFeature } from '@fonderie/billing';\n\nexport { OPERATIONS } from '@fonderie/permissions';\n\nexport type ExpressRequest = IncomingMessage & { body?: unknown; _fonderie?: IFonderieContext };\nexport type ExpressResponse = ServerResponse;\nexport type ExpressNext = (err?: unknown) => void;\n\n// ── Web Standard ↔ Express translation ───────────────────────────\n\nexport async function expressRequestToWeb(req: ExpressRequest): Promise<Request> {\n\tconst encrypted = (req.socket as { encrypted?: boolean }).encrypted;\n\tconst protocol = encrypted ? 'https' : 'http';\n\tconst host = req.headers['host'] ?? 'localhost';\n\tconst url = `${protocol}://${host}${req.url ?? '/'}`;\n\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(req.headers)) {\n\t\tif (!value) continue;\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const v of value) headers.append(key, v);\n\t\t} else {\n\t\t\theaders.set(key, value);\n\t\t}\n\t}\n\n\tconst method = req.method ?? 'GET';\n\tconst hasBody = !['GET', 'HEAD', 'OPTIONS'].includes(method.toUpperCase());\n\tconst body = hasBody ? await readStream(req) : null;\n\n\treturn new Request(url, { method, headers, body });\n}\n\nexport async function webResponseToExpress(webRes: Response, res: ExpressResponse): Promise<void> {\n\tres.statusCode = webRes.status;\n\twebRes.headers.forEach((value, key) => res.setHeader(key, value));\n\tres.end(Buffer.from(await webRes.arrayBuffer()));\n}\n\nfunction readStream(req: IncomingMessage): Promise<ArrayBuffer> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on('data', (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on('end', () => {\n\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\t// slice creates a correctly-sized ArrayBuffer (buf.buffer is a shared pool)\n\t\t\tresolve(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer);\n\t\t});\n\t\treq.on('error', reject);\n\t});\n}\n\n// ── bridge ────────────────────────────────────────────────────────\n//\n// Express middleware. Populates req._fonderie with the fonderie context\n// (user, workspace, meta) for all subsequent route handlers.\n// Also forwards the parsed body to req.body.\n//\n// app.use(bridge(fonderie))\n\nexport function bridge(fonderie: FonderieApp) {\n\treturn async (req: ExpressRequest, _res: ExpressResponse, next: ExpressNext) => {\n\t\ttry {\n\t\t\tconst webReq = await expressRequestToWeb(req);\n\t\t\t// Cache so the infra handler in mount() can reuse it without re-reading\n\t\t\t// the body stream (which can only be consumed once).\n\t\t\t(req as any)._fonterieReq = webReq;\n\t\t\treq._fonderie = await fonderie.buildContext(webReq.clone());\n\t\t\tif (req._fonderie.meta['body'] !== undefined) {\n\t\t\t\treq.body = req._fonderie.meta['body'];\n\t\t\t}\n\t\t\tnext();\n\t\t} catch (err) {\n\t\t\tnext(err);\n\t\t}\n\t};\n}\n\n// ── adapt ─────────────────────────────────────────────────────────\n//\n// Low-level escape hatch — wraps any fonderie Middleware into an Express\n// middleware function. Use this for custom fonderie middleware; prefer the\n// named exports below for the built-in fonderie guards.\n\nexport function adapt(middleware: Middleware) {\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tconst ctx = req._fonderie;\n\t\tif (!ctx) {\n\t\t\tnext(new Error('[fonderie] bridge() must be registered before adapt()'));\n\t\t\treturn;\n\t\t}\n\n\t\tlet continued = false;\n\t\tconst result = await middleware(ctx, async () => {\n\t\t\tcontinued = true;\n\t\t\treturn new Response();\n\t\t});\n\n\t\tif (continued) {\n\t\t\tnext();\n\t\t} else {\n\t\t\tawait webResponseToExpress(result, res);\n\t\t}\n\t};\n}\n\n// ── Pre-adapted middleware ────────────────────────────────────────\n//\n// Drop-in replacements for the fonderie middleware functions — no adapt()\n// needed. Import directly from this package instead of from the source\n// packages, and use them as native Express middleware.\n//\n// app.get('/jobs', requireAuth, withWorkspace(store), ...)\n\nexport const requireAuth = adapt(_requireAuth);\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]) {\n\treturn adapt(_withWorkspace(store));\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n) {\n\treturn adapt(_requirePermission(operation, permissionKey));\n}\n\nexport function requireFeature(key: string) {\n\treturn adapt(_requireFeature(key));\n}\n\n// ── mount ─────────────────────────────────────────────────────────\n//\n// Wires up fonderie to an Express app. Returns the same app so you can add\n// routes after mount() and before app.listen() — infra is sealed lazily\n// when app.listen() is first called:\n//\n// const api = mount(app, fonderie)\n// api.use(buildTodoRouter(store))\n// app.listen(port)\n//\n// Alternatively pass a register callback to be explicit about ordering:\n//\n// mount(app, fonderie, (app) => {\n// app.use(buildTodoRouter(store))\n// })\n\ntype ExpressApp = {\n\tuse: (...args: any[]) => any;\n\tall: (path: string, handler: (req: ExpressRequest, res: ExpressResponse) => void) => void;\n\tlisten: (...args: any[]) => any;\n};\n\nexport function mount<T extends ExpressApp>(\n\tapp: T,\n\tfonderie: FonderieApp,\n\tregister?: (app: T) => void,\n): T {\n\tconst infraHandler = async (req: ExpressRequest, res: ExpressResponse) => {\n\t\tconst webReq = (req as any)._fonterieReq as Request ?? await expressRequestToWeb(req);\n\t\tconst webRes = await fonderie.handle(webReq);\n\t\tawait webResponseToExpress(webRes, res);\n\t};\n\n\tapp.use(bridge(fonderie));\n\n\tif (register) {\n\t\tregister(app);\n\t\tapp.use(infraHandler);\n\t} else {\n\t\tlet sealed = false;\n\t\tconst origListen = app.listen.bind(app);\n\t\t(app as ExpressApp).listen = (...args: any[]) => {\n\t\t\tif (!sealed) {\n\t\t\t\tsealed = true;\n\t\t\t\tapp.use(infraHandler);\n\t\t\t}\n\t\t\t(app as ExpressApp).listen = origListen;\n\t\t\treturn origListen(...args);\n\t\t};\n\t}\n\n\treturn app;\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@fonderie/adapter-express",
3
+ "version": "1.0.0",
4
+ "description": "Express adapter for fonderie-js — bridge(), adapt(), mount() to use fonderie middleware in native Express routes.",
5
+ "keywords": [
6
+ "fonderie-js",
7
+ "express",
8
+ "adapter",
9
+ "middleware",
10
+ "saas",
11
+ "typescript"
12
+ ],
13
+ "license": "MIT",
14
+ "type": "module",
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "main": "./dist/index.cjs",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "dev": "tsup --watch",
31
+ "test": "tsx --test src/__tests__/*.test.ts",
32
+ "typecheck": "tsc --noEmit",
33
+ "lint": "biome lint src",
34
+ "format": "biome format --write src",
35
+ "check": "biome check --write src"
36
+ },
37
+ "peerDependencies": {
38
+ "@fonderie/core": "^0.1.0",
39
+ "@fonderie/workspaces": "^1.0.0",
40
+ "@fonderie/permissions": "^1.0.0",
41
+ "@fonderie/billing": "^1.0.0",
42
+ "express": "^4.0.0 || ^5.0.0"
43
+ },
44
+ "peerDependenciesMeta": {
45
+ "@fonderie/workspaces": {
46
+ "optional": true
47
+ },
48
+ "@fonderie/permissions": {
49
+ "optional": true
50
+ },
51
+ "@fonderie/billing": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "@fonderie/core": "../core",
57
+ "@fonderie/workspaces": "../workspaces",
58
+ "@fonderie/permissions": "../permissions",
59
+ "@fonderie/billing": "../billing",
60
+ "@types/node": "^25.6.0",
61
+ "tsx": "^4.21.0",
62
+ "tsup": "^8.5.1",
63
+ "typescript": "^6.0.3"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public"
67
+ },
68
+ "files": [
69
+ "dist",
70
+ "LICENSE",
71
+ "README.md"
72
+ ],
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "git+https://github.com/fonderie-js/sdk.git",
76
+ "directory": "packages/adapter-express"
77
+ },
78
+ "homepage": "https://github.com/fonderie-js/sdk/tree/main/packages/adapter-express#readme",
79
+ "bugs": {
80
+ "url": "https://github.com/fonderie-js/sdk/issues"
81
+ }
82
+ }