@fonderie/adapter-express 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -13,13 +13,31 @@ npm install @fonderie/adapter-express
13
13
  ## Use
14
14
 
15
15
  ```ts
16
- import { bridge, adapt, requireAuth } from '@fonderie/adapter-express';
17
- ```
16
+ import express from 'express';
17
+ import { mount, requireAuth, withWorkspace, type ExpressRequest } from '@fonderie/adapter-express';
18
+ import { buildFonderie } from './fonderie'; // your FonderieApp — see @fonderie/core
19
+
20
+ const { fonderie, store } = await buildFonderie();
21
+
22
+ const app = express();
23
+ app.use(express.json());
18
24
 
19
- Register `bridge(fonderie)` as global middleware first, then use the
20
- re-exported guards (`requireAuth`, `requireWorkspace`, `requirePermission`,
21
- `requireFeature`) directly on routes.
25
+ // mount() registers bridge() for you and seals fonderie's infra routes
26
+ // lazily at app.listen() add your own routes in between.
27
+ mount(app, fonderie);
28
+
29
+ app.get('/jobs', requireAuth, withWorkspace(store), (req, res) => {
30
+ const ctx = (req as ExpressRequest)._fonderie!;
31
+ res.json({ user: ctx.user, workspace: ctx.workspace });
32
+ });
33
+
34
+ app.listen(3000);
35
+ ```
22
36
 
37
+ The guards `withWorkspace`, `requirePermission`, and `requireFeature` load
38
+ their peer package lazily on first request — install `@fonderie/workspaces`,
39
+ `@fonderie/permissions`, or `@fonderie/billing` only if you use the matching
40
+ guard. For custom Fonderie middleware, wrap it with `adapt()`;
23
41
  `expressRequestToWeb` converts Express requests to web-standard `Request`
24
42
  objects for the Fonderie pipeline.
25
43
 
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,12 +17,20 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
- OPERATIONS: () => import_permissions2.OPERATIONS,
33
+ OPERATIONS: () => import_core.OPERATIONS,
24
34
  adapt: () => adapt,
25
35
  bridge: () => bridge,
26
36
  expressRequestToWeb: () => expressRequestToWeb,
@@ -33,10 +43,22 @@ __export(index_exports, {
33
43
  });
34
44
  module.exports = __toCommonJS(index_exports);
35
45
  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");
46
+ var import_core = require("@fonderie/core");
47
+ async function loadOptionalPeer(load, pkg, api) {
48
+ try {
49
+ return await load();
50
+ } catch (err) {
51
+ const e = err;
52
+ const notFound = e?.code === "ERR_MODULE_NOT_FOUND" || e?.code === "MODULE_NOT_FOUND";
53
+ const missing = notFound ? /Cannot find (?:package|module) '([^']+)'/.exec(e?.message ?? "")?.[1] : void 0;
54
+ if (missing === pkg || missing?.startsWith(pkg + "/")) {
55
+ throw new Error(
56
+ `[fonderie] ${api} requires the optional peer dependency "${pkg}". Install it: npm install ${pkg}`
57
+ );
58
+ }
59
+ throw err;
60
+ }
61
+ }
40
62
  async function expressRequestToWeb(req) {
41
63
  const encrypted = req.socket.encrypted;
42
64
  const protocol = encrypted ? "https" : "http";
@@ -108,13 +130,46 @@ function adapt(middleware) {
108
130
  }
109
131
  var requireAuth = adapt(import_middlewares.requireAuth);
110
132
  function withWorkspace(store) {
111
- return adapt((0, import_workspaces.withWorkspace)(store));
133
+ let inner;
134
+ return async (req, res, next) => {
135
+ if (!inner) {
136
+ const mod = await loadOptionalPeer(
137
+ () => import("@fonderie/workspaces"),
138
+ "@fonderie/workspaces",
139
+ "withWorkspace()"
140
+ );
141
+ inner = adapt(mod.withWorkspace(store));
142
+ }
143
+ return inner(req, res, next);
144
+ };
112
145
  }
113
146
  function requirePermission(operation, permissionKey) {
114
- return adapt((0, import_permissions.requirePermission)(operation, permissionKey));
147
+ let inner;
148
+ return async (req, res, next) => {
149
+ if (!inner) {
150
+ const mod = await loadOptionalPeer(
151
+ () => import("@fonderie/permissions"),
152
+ "@fonderie/permissions",
153
+ "requirePermission()"
154
+ );
155
+ inner = adapt(mod.requirePermission(operation, permissionKey));
156
+ }
157
+ return inner(req, res, next);
158
+ };
115
159
  }
116
160
  function requireFeature(key) {
117
- return adapt((0, import_billing.requireFeature)(key));
161
+ let inner;
162
+ return async (req, res, next) => {
163
+ if (!inner) {
164
+ const mod = await loadOptionalPeer(
165
+ () => import("@fonderie/billing"),
166
+ "@fonderie/billing",
167
+ "requireFeature()"
168
+ );
169
+ inner = adapt(mod.requireFeature(key));
170
+ }
171
+ return inner(req, res, next);
172
+ };
118
173
  }
119
174
  function mount(app, fonderie, register) {
120
175
  const infraHandler = async (req, res) => {
@@ -1 +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"]}
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';\n// Optional peers: type-only imports (erased at runtime). The guard factories\n// below load them lazily so installing this adapter never requires\n// @fonderie/workspaces, @fonderie/permissions, or @fonderie/billing unless\n// the corresponding guard is actually used.\nimport type { withWorkspace as _withWorkspace } from '@fonderie/workspaces';\nimport type { requirePermission as _requirePermission } from '@fonderie/permissions';\n\nexport { OPERATIONS } from '@fonderie/core';\n\nasync function loadOptionalPeer<T>(load: () => Promise<T>, pkg: string, api: string): Promise<T> {\n\ttry {\n\t\treturn await load();\n\t} catch (err) {\n\t\tconst e = err as { code?: string; message?: string } | undefined;\n\t\tconst notFound = e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND';\n\t\t// Only claim the peer is missing when the unresolved specifier IS the\n\t\t// peer — a transitive failure inside an installed peer must surface\n\t\t// as-is, not as a misleading install hint.\n\t\tconst missing = notFound ? /Cannot find (?:package|module) '([^']+)'/.exec(e?.message ?? '')?.[1] : undefined;\n\t\tif (missing === pkg || missing?.startsWith(pkg + '/')) {\n\t\t\tthrow new Error(\n\t\t\t\t`[fonderie] ${api} requires the optional peer dependency \"${pkg}\". Install it: npm install ${pkg}`,\n\t\t\t);\n\t\t}\n\t\tthrow err;\n\t}\n}\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\n// The three guards below wrap OPTIONAL peers, so the peer is imported lazily\n// on first request — not at module load. adapt() returns an async Express\n// middleware either way, so the extra await changes nothing for callers.\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/workspaces'),\n\t\t\t\t'@fonderie/workspaces',\n\t\t\t\t'withWorkspace()',\n\t\t\t);\n\t\t\tinner = adapt(mod.withWorkspace(store));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/permissions'),\n\t\t\t\t'@fonderie/permissions',\n\t\t\t\t'requirePermission()',\n\t\t\t);\n\t\t\tinner = adapt(mod.requirePermission(operation, permissionKey));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\n}\n\nexport function requireFeature(key: string) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/billing'),\n\t\t\t\t'@fonderie/billing',\n\t\t\t\t'requireFeature()',\n\t\t\t);\n\t\t\tinner = adapt(mod.requireFeature(key));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\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":["_requireAuth"]}
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import { IFonderieContext, Middleware, FonderieApp } from '@fonderie/core';
3
+ export { OPERATIONS } from '@fonderie/core';
3
4
  import { withWorkspace as withWorkspace$1 } from '@fonderie/workspaces';
4
5
  import { requirePermission as requirePermission$1 } from '@fonderie/permissions';
5
- export { OPERATIONS } from '@fonderie/permissions';
6
6
 
7
7
  type ExpressRequest = IncomingMessage & {
8
8
  body?: unknown;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import { IFonderieContext, Middleware, FonderieApp } from '@fonderie/core';
3
+ export { OPERATIONS } from '@fonderie/core';
3
4
  import { withWorkspace as withWorkspace$1 } from '@fonderie/workspaces';
4
5
  import { requirePermission as requirePermission$1 } from '@fonderie/permissions';
5
- export { OPERATIONS } from '@fonderie/permissions';
6
6
 
7
7
  type ExpressRequest = IncomingMessage & {
8
8
  body?: unknown;
package/dist/index.js CHANGED
@@ -1,9 +1,21 @@
1
1
  // src/index.ts
2
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";
3
+ import { OPERATIONS } from "@fonderie/core";
4
+ async function loadOptionalPeer(load, pkg, api) {
5
+ try {
6
+ return await load();
7
+ } catch (err) {
8
+ const e = err;
9
+ const notFound = e?.code === "ERR_MODULE_NOT_FOUND" || e?.code === "MODULE_NOT_FOUND";
10
+ const missing = notFound ? /Cannot find (?:package|module) '([^']+)'/.exec(e?.message ?? "")?.[1] : void 0;
11
+ if (missing === pkg || missing?.startsWith(pkg + "/")) {
12
+ throw new Error(
13
+ `[fonderie] ${api} requires the optional peer dependency "${pkg}". Install it: npm install ${pkg}`
14
+ );
15
+ }
16
+ throw err;
17
+ }
18
+ }
7
19
  async function expressRequestToWeb(req) {
8
20
  const encrypted = req.socket.encrypted;
9
21
  const protocol = encrypted ? "https" : "http";
@@ -75,13 +87,46 @@ function adapt(middleware) {
75
87
  }
76
88
  var requireAuth = adapt(_requireAuth);
77
89
  function withWorkspace(store) {
78
- return adapt(_withWorkspace(store));
90
+ let inner;
91
+ return async (req, res, next) => {
92
+ if (!inner) {
93
+ const mod = await loadOptionalPeer(
94
+ () => import("@fonderie/workspaces"),
95
+ "@fonderie/workspaces",
96
+ "withWorkspace()"
97
+ );
98
+ inner = adapt(mod.withWorkspace(store));
99
+ }
100
+ return inner(req, res, next);
101
+ };
79
102
  }
80
103
  function requirePermission(operation, permissionKey) {
81
- return adapt(_requirePermission(operation, permissionKey));
104
+ let inner;
105
+ return async (req, res, next) => {
106
+ if (!inner) {
107
+ const mod = await loadOptionalPeer(
108
+ () => import("@fonderie/permissions"),
109
+ "@fonderie/permissions",
110
+ "requirePermission()"
111
+ );
112
+ inner = adapt(mod.requirePermission(operation, permissionKey));
113
+ }
114
+ return inner(req, res, next);
115
+ };
82
116
  }
83
117
  function requireFeature(key) {
84
- return adapt(_requireFeature(key));
118
+ let inner;
119
+ return async (req, res, next) => {
120
+ if (!inner) {
121
+ const mod = await loadOptionalPeer(
122
+ () => import("@fonderie/billing"),
123
+ "@fonderie/billing",
124
+ "requireFeature()"
125
+ );
126
+ inner = adapt(mod.requireFeature(key));
127
+ }
128
+ return inner(req, res, next);
129
+ };
85
130
  }
86
131
  function mount(app, fonderie, register) {
87
132
  const infraHandler = async (req, res) => {
package/dist/index.js.map CHANGED
@@ -1 +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":[]}
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';\n// Optional peers: type-only imports (erased at runtime). The guard factories\n// below load them lazily so installing this adapter never requires\n// @fonderie/workspaces, @fonderie/permissions, or @fonderie/billing unless\n// the corresponding guard is actually used.\nimport type { withWorkspace as _withWorkspace } from '@fonderie/workspaces';\nimport type { requirePermission as _requirePermission } from '@fonderie/permissions';\n\nexport { OPERATIONS } from '@fonderie/core';\n\nasync function loadOptionalPeer<T>(load: () => Promise<T>, pkg: string, api: string): Promise<T> {\n\ttry {\n\t\treturn await load();\n\t} catch (err) {\n\t\tconst e = err as { code?: string; message?: string } | undefined;\n\t\tconst notFound = e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND';\n\t\t// Only claim the peer is missing when the unresolved specifier IS the\n\t\t// peer — a transitive failure inside an installed peer must surface\n\t\t// as-is, not as a misleading install hint.\n\t\tconst missing = notFound ? /Cannot find (?:package|module) '([^']+)'/.exec(e?.message ?? '')?.[1] : undefined;\n\t\tif (missing === pkg || missing?.startsWith(pkg + '/')) {\n\t\t\tthrow new Error(\n\t\t\t\t`[fonderie] ${api} requires the optional peer dependency \"${pkg}\". Install it: npm install ${pkg}`,\n\t\t\t);\n\t\t}\n\t\tthrow err;\n\t}\n}\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\n// The three guards below wrap OPTIONAL peers, so the peer is imported lazily\n// on first request — not at module load. adapt() returns an async Express\n// middleware either way, so the extra await changes nothing for callers.\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/workspaces'),\n\t\t\t\t'@fonderie/workspaces',\n\t\t\t\t'withWorkspace()',\n\t\t\t);\n\t\t\tinner = adapt(mod.withWorkspace(store));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/permissions'),\n\t\t\t\t'@fonderie/permissions',\n\t\t\t\t'requirePermission()',\n\t\t\t);\n\t\t\tinner = adapt(mod.requirePermission(operation, permissionKey));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\n}\n\nexport function requireFeature(key: string) {\n\tlet inner: ReturnType<typeof adapt> | undefined;\n\treturn async (req: ExpressRequest, res: ExpressResponse, next: ExpressNext) => {\n\t\tif (!inner) {\n\t\t\tconst mod = await loadOptionalPeer(\n\t\t\t\t() => import('@fonderie/billing'),\n\t\t\t\t'@fonderie/billing',\n\t\t\t\t'requireFeature()',\n\t\t\t);\n\t\t\tinner = adapt(mod.requireFeature(key));\n\t\t}\n\t\treturn inner(req, res, next);\n\t};\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonderie/adapter-express",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Express adapter for fonderie-js — bridge(), adapt(), mount() to use fonderie middleware in native Express routes.",
5
5
  "keywords": [
6
6
  "fonderie-js",
@@ -35,10 +35,10 @@
35
35
  "check": "biome check --write src"
36
36
  },
37
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",
38
+ "@fonderie/core": "^0.1.1",
39
+ "@fonderie/workspaces": "^1.0.1",
40
+ "@fonderie/permissions": "^1.0.1",
41
+ "@fonderie/billing": "^1.0.1",
42
42
  "express": "^4.0.0 || ^5.0.0"
43
43
  },
44
44
  "peerDependenciesMeta": {