@fonderie/adapter-hono 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 +23 -5
- package/dist/index.cjs +63 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +52 -7
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -13,13 +13,31 @@ npm install @fonderie/adapter-hono
|
|
|
13
13
|
## Use
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
17
|
-
|
|
16
|
+
import { Hono } from 'hono';
|
|
17
|
+
import { mount, bridge, requireAuth, withWorkspace } from '@fonderie/adapter-hono';
|
|
18
|
+
import { buildFonderie } from './fonderie'; // your FonderieApp — see @fonderie/core
|
|
19
|
+
|
|
20
|
+
const { fonderie, store } = await buildFonderie();
|
|
21
|
+
|
|
22
|
+
const hono = new Hono();
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
// bridge() populates c.get('_fonderie') for your routes; mount() registers
|
|
25
|
+
// fonderie's infra routes as the notFound fallback, so your routes win.
|
|
26
|
+
hono.use('*', bridge(fonderie));
|
|
27
|
+
mount(hono, fonderie);
|
|
28
|
+
|
|
29
|
+
hono.get('/jobs', requireAuth, withWorkspace(store), (c) => {
|
|
30
|
+
const ctx = c.get('_fonderie');
|
|
31
|
+
return c.json({ user: ctx.user, workspace: ctx.workspace });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export default hono;
|
|
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
|
`ContextVariableMap` is augmented so `c.get('_fonderie')` is fully typed;
|
|
24
42
|
`FonderieVariables` is exported for typing your `Hono` instance.
|
|
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: () =>
|
|
33
|
+
OPERATIONS: () => import_core.OPERATIONS,
|
|
24
34
|
adapt: () => adapt,
|
|
25
35
|
bridge: () => bridge,
|
|
26
36
|
mount: () => mount,
|
|
@@ -31,10 +41,22 @@ __export(index_exports, {
|
|
|
31
41
|
});
|
|
32
42
|
module.exports = __toCommonJS(index_exports);
|
|
33
43
|
var import_middlewares = require("@fonderie/core/middlewares");
|
|
34
|
-
var
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
var import_core = require("@fonderie/core");
|
|
45
|
+
async function loadOptionalPeer(load, pkg, api) {
|
|
46
|
+
try {
|
|
47
|
+
return await load();
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const e = err;
|
|
50
|
+
const notFound = e?.code === "ERR_MODULE_NOT_FOUND" || e?.code === "MODULE_NOT_FOUND";
|
|
51
|
+
const missing = notFound ? /Cannot find (?:package|module) '([^']+)'/.exec(e?.message ?? "")?.[1] : void 0;
|
|
52
|
+
if (missing === pkg || missing?.startsWith(pkg + "/")) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`[fonderie] ${api} requires the optional peer dependency "${pkg}". Install it: npm install ${pkg}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
38
60
|
function bridge(fonderie) {
|
|
39
61
|
return async (c, next) => {
|
|
40
62
|
const ctx = await fonderie.buildContext(c.req.raw.clone());
|
|
@@ -60,13 +82,46 @@ function adapt(middleware) {
|
|
|
60
82
|
}
|
|
61
83
|
var requireAuth = adapt(import_middlewares.requireAuth);
|
|
62
84
|
function withWorkspace(store) {
|
|
63
|
-
|
|
85
|
+
let inner;
|
|
86
|
+
return async (c, next) => {
|
|
87
|
+
if (!inner) {
|
|
88
|
+
const mod = await loadOptionalPeer(
|
|
89
|
+
() => import("@fonderie/workspaces"),
|
|
90
|
+
"@fonderie/workspaces",
|
|
91
|
+
"withWorkspace()"
|
|
92
|
+
);
|
|
93
|
+
inner = adapt(mod.withWorkspace(store));
|
|
94
|
+
}
|
|
95
|
+
return inner(c, next);
|
|
96
|
+
};
|
|
64
97
|
}
|
|
65
98
|
function requirePermission(operation, permissionKey) {
|
|
66
|
-
|
|
99
|
+
let inner;
|
|
100
|
+
return async (c, next) => {
|
|
101
|
+
if (!inner) {
|
|
102
|
+
const mod = await loadOptionalPeer(
|
|
103
|
+
() => import("@fonderie/permissions"),
|
|
104
|
+
"@fonderie/permissions",
|
|
105
|
+
"requirePermission()"
|
|
106
|
+
);
|
|
107
|
+
inner = adapt(mod.requirePermission(operation, permissionKey));
|
|
108
|
+
}
|
|
109
|
+
return inner(c, next);
|
|
110
|
+
};
|
|
67
111
|
}
|
|
68
112
|
function requireFeature(key) {
|
|
69
|
-
|
|
113
|
+
let inner;
|
|
114
|
+
return async (c, next) => {
|
|
115
|
+
if (!inner) {
|
|
116
|
+
const mod = await loadOptionalPeer(
|
|
117
|
+
() => import("@fonderie/billing"),
|
|
118
|
+
"@fonderie/billing",
|
|
119
|
+
"requireFeature()"
|
|
120
|
+
);
|
|
121
|
+
inner = adapt(mod.requireFeature(key));
|
|
122
|
+
}
|
|
123
|
+
return inner(c, next);
|
|
124
|
+
};
|
|
70
125
|
}
|
|
71
126
|
function mount(hono, fonderie) {
|
|
72
127
|
hono.notFound((c) => fonderie.handle(c.req.raw));
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport type { Hono } from 'hono';\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';\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport type { Hono } from 'hono';\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\n// Augment Hono's ContextVariableMap so c.get('_fonderie') is typed.\ndeclare module 'hono' {\n\tinterface ContextVariableMap {\n\t\t_fonderie: IFonderieContext;\n\t}\n}\n\n// Re-export for consumers who want to type their Hono app:\n// const hono = new Hono<{ Variables: FonderieVariables }>()\nexport type FonderieVariables = {\n\t_fonderie: IFonderieContext;\n};\n\n// ── bridge ────────────────────────────────────────────────────────\n//\n// Global middleware. Runs fonderie's session + billing global stack so that\n// ctx.user and ctx.meta['billing'] are available in every route handler.\n// Must be registered before any fonderie-aware route middleware.\n//\n// hono.use('*', bridge(fonderie))\n\nexport function bridge(fonderie: FonderieApp): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\tconst ctx = await fonderie.buildContext(c.req.raw.clone());\n\t\tc.set('_fonderie', ctx);\n\t\tawait next();\n\t};\n}\n\n// ── adapt ─────────────────────────────────────────────────────────\n//\n// Low-level escape hatch — wraps any fonderie Middleware into a Hono\n// MiddlewareHandler. Use this for custom fonderie middleware; prefer the\n// named exports below for the built-in fonderie guards.\n\nexport function adapt(middleware: Middleware): MiddlewareHandler {\n\treturn async (c: Context, next) => {\n\t\tconst ctx = c.get('_fonderie');\n\t\tif (!ctx) throw new Error('[fonderie] bridge() must be registered before adapt()');\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\tawait next();\n\t\t} else {\n\t\t\treturn result;\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 Hono middleware.\n//\n// hono.get('/jobs', requireAuth, withWorkspace(store), ...)\n\nexport const requireAuth: MiddlewareHandler = 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. MiddlewareHandler is async either\n// way, so the extra await changes nothing for callers.\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\nexport function requireFeature(key: string): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\n// ── mount ─────────────────────────────────────────────────────────\n//\n// Wires up fonderie to a Hono app. Returns the same app so you can add\n// routes after mount() — fonderie infra is the notFound handler, so\n// user routes always take priority:\n//\n// const api = mount(hono, fonderie)\n// api.get('/v1/todos', requireAuth, handler)\n// export default hono\n\n// mount() wires fonderie's infrastructure routes as the notFound fallback so\n// user routes always take priority. Call bridge() yourself before your routes\n// to ensure _fonderie is populated for them.\nexport function mount(hono: Hono, fonderie: FonderieApp): Hono {\n\thono.notFound((c) => fonderie.handle(c.req.raw));\n\treturn hono;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,yBAA4C;AAQ5C,kBAA2B;AAE3B,eAAe,iBAAoB,MAAwB,KAAa,KAAyB;AAChG,MAAI;AACH,WAAO,MAAM,KAAK;AAAA,EACnB,SAAS,KAAK;AACb,UAAM,IAAI;AACV,UAAM,WAAW,GAAG,SAAS,0BAA0B,GAAG,SAAS;AAInE,UAAM,UAAU,WAAW,2CAA2C,KAAK,GAAG,WAAW,EAAE,IAAI,CAAC,IAAI;AACpG,QAAI,YAAY,OAAO,SAAS,WAAW,MAAM,GAAG,GAAG;AACtD,YAAM,IAAI;AAAA,QACT,cAAc,GAAG,2CAA2C,GAAG,8BAA8B,GAAG;AAAA,MACjG;AAAA,IACD;AACA,UAAM;AAAA,EACP;AACD;AAuBO,SAAS,OAAO,UAA0C;AAChE,SAAO,OAAO,GAAG,SAAS;AACzB,UAAM,MAAM,MAAM,SAAS,aAAa,EAAE,IAAI,IAAI,MAAM,CAAC;AACzD,MAAE,IAAI,aAAa,GAAG;AACtB,UAAM,KAAK;AAAA,EACZ;AACD;AAQO,SAAS,MAAM,YAA2C;AAChE,SAAO,OAAO,GAAY,SAAS;AAClC,UAAM,MAAM,EAAE,IAAI,WAAW;AAC7B,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uDAAuD;AAEjF,QAAI,YAAY;AAChB,UAAM,SAAS,MAAM,WAAW,KAAK,YAAY;AAChD,kBAAY;AACZ,aAAO,IAAI,SAAS;AAAA,IACrB,CAAC;AAED,QAAI,WAAW;AACd,YAAM,KAAK;AAAA,IACZ,OAAO;AACN,aAAO;AAAA,IACR;AAAA,EACD;AACD;AAUO,IAAM,cAAiC,MAAM,mBAAAA,WAAY;AAMzD,SAAS,cAAc,OAAgE;AAC7F,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,sBAAsB;AAAA,QACnC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,cAAc,KAAK,CAAC;AAAA,IACvC;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAEO,SAAS,kBACf,WACA,eACoB;AACpB,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,uBAAuB;AAAA,QACpC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,kBAAkB,WAAW,aAAa,CAAC;AAAA,IAC9D;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAEO,SAAS,eAAe,KAAgC;AAC9D,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,mBAAmB;AAAA,QAChC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,eAAe,GAAG,CAAC;AAAA,IACtC;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAeO,SAAS,MAAM,MAAY,UAA6B;AAC9D,OAAK,SAAS,CAAC,MAAM,SAAS,OAAO,EAAE,IAAI,GAAG,CAAC;AAC/C,SAAO;AACR;","names":["_requireAuth"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MiddlewareHandler, Hono } from 'hono';
|
|
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
|
declare module 'hono' {
|
|
8
8
|
interface ContextVariableMap {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MiddlewareHandler, Hono } from 'hono';
|
|
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
|
declare module 'hono' {
|
|
8
8
|
interface ContextVariableMap {
|
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 {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
function bridge(fonderie) {
|
|
8
20
|
return async (c, next) => {
|
|
9
21
|
const ctx = await fonderie.buildContext(c.req.raw.clone());
|
|
@@ -29,13 +41,46 @@ function adapt(middleware) {
|
|
|
29
41
|
}
|
|
30
42
|
var requireAuth = adapt(_requireAuth);
|
|
31
43
|
function withWorkspace(store) {
|
|
32
|
-
|
|
44
|
+
let inner;
|
|
45
|
+
return async (c, next) => {
|
|
46
|
+
if (!inner) {
|
|
47
|
+
const mod = await loadOptionalPeer(
|
|
48
|
+
() => import("@fonderie/workspaces"),
|
|
49
|
+
"@fonderie/workspaces",
|
|
50
|
+
"withWorkspace()"
|
|
51
|
+
);
|
|
52
|
+
inner = adapt(mod.withWorkspace(store));
|
|
53
|
+
}
|
|
54
|
+
return inner(c, next);
|
|
55
|
+
};
|
|
33
56
|
}
|
|
34
57
|
function requirePermission(operation, permissionKey) {
|
|
35
|
-
|
|
58
|
+
let inner;
|
|
59
|
+
return async (c, next) => {
|
|
60
|
+
if (!inner) {
|
|
61
|
+
const mod = await loadOptionalPeer(
|
|
62
|
+
() => import("@fonderie/permissions"),
|
|
63
|
+
"@fonderie/permissions",
|
|
64
|
+
"requirePermission()"
|
|
65
|
+
);
|
|
66
|
+
inner = adapt(mod.requirePermission(operation, permissionKey));
|
|
67
|
+
}
|
|
68
|
+
return inner(c, next);
|
|
69
|
+
};
|
|
36
70
|
}
|
|
37
71
|
function requireFeature(key) {
|
|
38
|
-
|
|
72
|
+
let inner;
|
|
73
|
+
return async (c, next) => {
|
|
74
|
+
if (!inner) {
|
|
75
|
+
const mod = await loadOptionalPeer(
|
|
76
|
+
() => import("@fonderie/billing"),
|
|
77
|
+
"@fonderie/billing",
|
|
78
|
+
"requireFeature()"
|
|
79
|
+
);
|
|
80
|
+
inner = adapt(mod.requireFeature(key));
|
|
81
|
+
}
|
|
82
|
+
return inner(c, next);
|
|
83
|
+
};
|
|
39
84
|
}
|
|
40
85
|
function mount(hono, fonderie) {
|
|
41
86
|
hono.notFound((c) => fonderie.handle(c.req.raw));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport type { Hono } from 'hono';\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';\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport type { Hono } from 'hono';\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\n// Augment Hono's ContextVariableMap so c.get('_fonderie') is typed.\ndeclare module 'hono' {\n\tinterface ContextVariableMap {\n\t\t_fonderie: IFonderieContext;\n\t}\n}\n\n// Re-export for consumers who want to type their Hono app:\n// const hono = new Hono<{ Variables: FonderieVariables }>()\nexport type FonderieVariables = {\n\t_fonderie: IFonderieContext;\n};\n\n// ── bridge ────────────────────────────────────────────────────────\n//\n// Global middleware. Runs fonderie's session + billing global stack so that\n// ctx.user and ctx.meta['billing'] are available in every route handler.\n// Must be registered before any fonderie-aware route middleware.\n//\n// hono.use('*', bridge(fonderie))\n\nexport function bridge(fonderie: FonderieApp): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\tconst ctx = await fonderie.buildContext(c.req.raw.clone());\n\t\tc.set('_fonderie', ctx);\n\t\tawait next();\n\t};\n}\n\n// ── adapt ─────────────────────────────────────────────────────────\n//\n// Low-level escape hatch — wraps any fonderie Middleware into a Hono\n// MiddlewareHandler. Use this for custom fonderie middleware; prefer the\n// named exports below for the built-in fonderie guards.\n\nexport function adapt(middleware: Middleware): MiddlewareHandler {\n\treturn async (c: Context, next) => {\n\t\tconst ctx = c.get('_fonderie');\n\t\tif (!ctx) throw new Error('[fonderie] bridge() must be registered before adapt()');\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\tawait next();\n\t\t} else {\n\t\t\treturn result;\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 Hono middleware.\n//\n// hono.get('/jobs', requireAuth, withWorkspace(store), ...)\n\nexport const requireAuth: MiddlewareHandler = 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. MiddlewareHandler is async either\n// way, so the extra await changes nothing for callers.\n\nexport function withWorkspace(store: Parameters<typeof _withWorkspace>[0]): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\nexport function requirePermission(\n\toperation: Parameters<typeof _requirePermission>[0],\n\tpermissionKey: Parameters<typeof _requirePermission>[1],\n): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\nexport function requireFeature(key: string): MiddlewareHandler {\n\tlet inner: MiddlewareHandler | undefined;\n\treturn async (c, next) => {\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(c, next);\n\t};\n}\n\n// ── mount ─────────────────────────────────────────────────────────\n//\n// Wires up fonderie to a Hono app. Returns the same app so you can add\n// routes after mount() — fonderie infra is the notFound handler, so\n// user routes always take priority:\n//\n// const api = mount(hono, fonderie)\n// api.get('/v1/todos', requireAuth, handler)\n// export default hono\n\n// mount() wires fonderie's infrastructure routes as the notFound fallback so\n// user routes always take priority. Call bridge() yourself before your routes\n// to ensure _fonderie is populated for them.\nexport function mount(hono: Hono, fonderie: FonderieApp): Hono {\n\thono.notFound((c) => fonderie.handle(c.req.raw));\n\treturn hono;\n}\n"],"mappings":";AAIA,SAAS,eAAe,oBAAoB;AAQ5C,SAAS,kBAAkB;AAE3B,eAAe,iBAAoB,MAAwB,KAAa,KAAyB;AAChG,MAAI;AACH,WAAO,MAAM,KAAK;AAAA,EACnB,SAAS,KAAK;AACb,UAAM,IAAI;AACV,UAAM,WAAW,GAAG,SAAS,0BAA0B,GAAG,SAAS;AAInE,UAAM,UAAU,WAAW,2CAA2C,KAAK,GAAG,WAAW,EAAE,IAAI,CAAC,IAAI;AACpG,QAAI,YAAY,OAAO,SAAS,WAAW,MAAM,GAAG,GAAG;AACtD,YAAM,IAAI;AAAA,QACT,cAAc,GAAG,2CAA2C,GAAG,8BAA8B,GAAG;AAAA,MACjG;AAAA,IACD;AACA,UAAM;AAAA,EACP;AACD;AAuBO,SAAS,OAAO,UAA0C;AAChE,SAAO,OAAO,GAAG,SAAS;AACzB,UAAM,MAAM,MAAM,SAAS,aAAa,EAAE,IAAI,IAAI,MAAM,CAAC;AACzD,MAAE,IAAI,aAAa,GAAG;AACtB,UAAM,KAAK;AAAA,EACZ;AACD;AAQO,SAAS,MAAM,YAA2C;AAChE,SAAO,OAAO,GAAY,SAAS;AAClC,UAAM,MAAM,EAAE,IAAI,WAAW;AAC7B,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uDAAuD;AAEjF,QAAI,YAAY;AAChB,UAAM,SAAS,MAAM,WAAW,KAAK,YAAY;AAChD,kBAAY;AACZ,aAAO,IAAI,SAAS;AAAA,IACrB,CAAC;AAED,QAAI,WAAW;AACd,YAAM,KAAK;AAAA,IACZ,OAAO;AACN,aAAO;AAAA,IACR;AAAA,EACD;AACD;AAUO,IAAM,cAAiC,MAAM,YAAY;AAMzD,SAAS,cAAc,OAAgE;AAC7F,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,sBAAsB;AAAA,QACnC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,cAAc,KAAK,CAAC;AAAA,IACvC;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAEO,SAAS,kBACf,WACA,eACoB;AACpB,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,uBAAuB;AAAA,QACpC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,kBAAkB,WAAW,aAAa,CAAC;AAAA,IAC9D;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAEO,SAAS,eAAe,KAAgC;AAC9D,MAAI;AACJ,SAAO,OAAO,GAAG,SAAS;AACzB,QAAI,CAAC,OAAO;AACX,YAAM,MAAM,MAAM;AAAA,QACjB,MAAM,OAAO,mBAAmB;AAAA,QAChC;AAAA,QACA;AAAA,MACD;AACA,cAAQ,MAAM,IAAI,eAAe,GAAG,CAAC;AAAA,IACtC;AACA,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB;AACD;AAeO,SAAS,MAAM,MAAY,UAA6B;AAC9D,OAAK,SAAS,CAAC,MAAM,SAAS,OAAO,EAAE,IAAI,GAAG,CAAC;AAC/C,SAAO;AACR;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonderie/adapter-hono",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Hono adapter for fonderie-js — bridge(), adapt(), mount() to use fonderie middleware in native Hono 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.
|
|
39
|
-
"@fonderie/workspaces": "^1.0.
|
|
40
|
-
"@fonderie/permissions": "^1.0.
|
|
41
|
-
"@fonderie/billing": "^1.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
|
"hono": "^4.0.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|