@mantajs/adapter-h3 0.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.d.ts +120 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +556 -0
- package/dist/adapter.js.map +1 -0
- package/dist/app.d.ts +68 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +150 -0
- package/dist/app.js.map +1 -0
- package/dist/handler.d.ts +18 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +63 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline.d.ts +46 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +108 -0
- package/dist/pipeline.js.map +1 -0
- package/package.json +24 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { IHttpPort } from '@mantajs/core/ports';
|
|
2
|
+
import { createApp } from 'h3';
|
|
3
|
+
type App = ReturnType<typeof createApp>;
|
|
4
|
+
export interface AuthContext {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export type AuthVerifier = (token: string) => Promise<AuthContext | null>;
|
|
10
|
+
export type SessionVerifier = (sessionId: string) => Promise<AuthContext | null>;
|
|
11
|
+
/** Custom middleware handler for a context (from src/middleware/{ctx}.ts). */
|
|
12
|
+
export type ContextMiddlewareHandler = (req: {
|
|
13
|
+
method: string;
|
|
14
|
+
url: string;
|
|
15
|
+
headers: Record<string, string | string[] | undefined>;
|
|
16
|
+
body?: unknown;
|
|
17
|
+
}, authContext: AuthContext | null) => Promise<AuthContext | null>;
|
|
18
|
+
/** Per-context auth rule registered by defineUser via bootstrap. */
|
|
19
|
+
interface ContextAuthRule {
|
|
20
|
+
prefix: string;
|
|
21
|
+
actorType: string;
|
|
22
|
+
publicPaths: Set<string>;
|
|
23
|
+
customMiddleware?: ContextMiddlewareHandler;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Routes that do NOT require authentication.
|
|
27
|
+
* Checks per-context public paths registered by defineUser.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isPublicRoute(path: string, contextRules?: ContextAuthRule[]): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Determines if a path requires authentication.
|
|
32
|
+
* Any /api/{ctx}/* path where a defineUser(ctx) exists requires auth (except public paths).
|
|
33
|
+
*/
|
|
34
|
+
export declare function requiresAuthentication(path: string, contextRules?: ContextAuthRule[]): boolean;
|
|
35
|
+
export interface RouteOptions {
|
|
36
|
+
bodySchema?: {
|
|
37
|
+
parse: (data: unknown) => unknown;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface RateLimitOptions {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
windowMs?: number;
|
|
43
|
+
maxRequests?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Readiness probe — a single infrastructure health check (DB, cache, eventbus).
|
|
47
|
+
* Each probe is awaited with a short timeout by the /health/ready handler.
|
|
48
|
+
* A probe that throws or resolves to false is reported as 'error'.
|
|
49
|
+
*/
|
|
50
|
+
export type ReadinessProbe = () => Promise<boolean>;
|
|
51
|
+
export interface H3AdapterOptions {
|
|
52
|
+
port?: number;
|
|
53
|
+
host?: string;
|
|
54
|
+
isDev?: boolean;
|
|
55
|
+
allowedOrigins?: string[];
|
|
56
|
+
rateLimit?: RateLimitOptions;
|
|
57
|
+
sessionVerifier?: SessionVerifier;
|
|
58
|
+
/**
|
|
59
|
+
* Optional set of readiness probes wired by the bootstrap layer.
|
|
60
|
+
* Only configured ports are included — absent infra is simply omitted
|
|
61
|
+
* from the checks payload, never reported as failing.
|
|
62
|
+
*/
|
|
63
|
+
readinessProbes?: Record<string, ReadinessProbe>;
|
|
64
|
+
/**
|
|
65
|
+
* Timeout in ms for each readiness probe (default 500ms).
|
|
66
|
+
* Probes that exceed this budget are reported as 'error'.
|
|
67
|
+
*/
|
|
68
|
+
readinessTimeoutMs?: number;
|
|
69
|
+
}
|
|
70
|
+
export declare class H3Adapter implements IHttpPort {
|
|
71
|
+
private _app;
|
|
72
|
+
private _router;
|
|
73
|
+
private _server;
|
|
74
|
+
private _startedAt;
|
|
75
|
+
private _isDev;
|
|
76
|
+
private _port;
|
|
77
|
+
private _host;
|
|
78
|
+
private _authVerifier;
|
|
79
|
+
private _sessionVerifier;
|
|
80
|
+
private _rbacEnabled;
|
|
81
|
+
private _allowedOrigins?;
|
|
82
|
+
private _options;
|
|
83
|
+
private _rateLimits;
|
|
84
|
+
private _contextAuthRules;
|
|
85
|
+
constructor(options?: H3AdapterOptions);
|
|
86
|
+
/** Expose the underlying H3 App for embedding in hosts (e.g. Nitro). */
|
|
87
|
+
getApp(): App;
|
|
88
|
+
setAuthVerifier(verifier: AuthVerifier): void;
|
|
89
|
+
setSessionVerifier(verifier: SessionVerifier): void;
|
|
90
|
+
/**
|
|
91
|
+
* Register per-context auth rules (from defineUser).
|
|
92
|
+
* Paths under /api/{ctx}/ will require JWT with matching actor_type,
|
|
93
|
+
* except for public paths (login, forgot-password, etc.).
|
|
94
|
+
*/
|
|
95
|
+
registerContextAuth(contextName: string, actorType: string, publicPaths: string[], customMiddleware?: ContextMiddlewareHandler): void;
|
|
96
|
+
enableRbac(enabled: boolean): void;
|
|
97
|
+
registerRoute(method: string, path: string, handler: (req: Request) => Promise<Response> | Response, options?: RouteOptions): void;
|
|
98
|
+
handleRequest(req: Request): Promise<Response>;
|
|
99
|
+
listen(): Promise<void>;
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
get port(): number;
|
|
102
|
+
private _runPipeline;
|
|
103
|
+
private _checkRateLimit;
|
|
104
|
+
private _runAuthStep;
|
|
105
|
+
private _runValidationStep;
|
|
106
|
+
private _runRbacStep;
|
|
107
|
+
private _registerHealthRoutes;
|
|
108
|
+
private _handleHealthRequest;
|
|
109
|
+
/**
|
|
110
|
+
* BC-F22 — Run all configured readiness probes with a per-probe timeout.
|
|
111
|
+
* Absent probes are simply omitted from the checks object (never reported
|
|
112
|
+
* as failures). Returns HTTP 200 when every probe passes, 503 otherwise.
|
|
113
|
+
*/
|
|
114
|
+
private _computeReadiness;
|
|
115
|
+
private _internalRoutes;
|
|
116
|
+
private _registerInternalRoute;
|
|
117
|
+
private _internalHandleRequest;
|
|
118
|
+
}
|
|
119
|
+
export {};
|
|
120
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
// SPEC-039 — H3Adapter implements IHttpPort
|
|
2
|
+
import { MantaError } from '@mantajs/core/errors';
|
|
3
|
+
import { createApp, createRouter, defineEventHandler, getMethod, getRequestHeader, setResponseHeader, setResponseStatus, toNodeListener, } from 'h3';
|
|
4
|
+
import { extractRequestId, mapErrorToResponse, parseBody, setCorsHeaders, setSecurityHeaders } from './pipeline';
|
|
5
|
+
/**
|
|
6
|
+
* Routes that do NOT require authentication.
|
|
7
|
+
* Checks per-context public paths registered by defineUser.
|
|
8
|
+
*/
|
|
9
|
+
export function isPublicRoute(path, contextRules) {
|
|
10
|
+
if (contextRules) {
|
|
11
|
+
for (const rule of contextRules) {
|
|
12
|
+
if (isContextPublicPath(path, rule))
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Determines if a path requires authentication.
|
|
20
|
+
* Any /api/{ctx}/* path where a defineUser(ctx) exists requires auth (except public paths).
|
|
21
|
+
*/
|
|
22
|
+
export function requiresAuthentication(path, contextRules) {
|
|
23
|
+
if (contextRules) {
|
|
24
|
+
for (const rule of contextRules) {
|
|
25
|
+
if (path.startsWith(rule.prefix)) {
|
|
26
|
+
return !isContextPublicPath(path, rule);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
function isContextPublicPath(path, rule) {
|
|
33
|
+
if (rule.publicPaths.has(path))
|
|
34
|
+
return true;
|
|
35
|
+
return path.startsWith(`${rule.prefix}_workflow/`) && path.endsWith('/resume');
|
|
36
|
+
}
|
|
37
|
+
export class H3Adapter {
|
|
38
|
+
_app;
|
|
39
|
+
_router;
|
|
40
|
+
_server = null;
|
|
41
|
+
_startedAt;
|
|
42
|
+
_isDev;
|
|
43
|
+
_port;
|
|
44
|
+
_host;
|
|
45
|
+
_authVerifier = null;
|
|
46
|
+
_sessionVerifier = null;
|
|
47
|
+
_rbacEnabled = false;
|
|
48
|
+
_allowedOrigins;
|
|
49
|
+
_options;
|
|
50
|
+
_rateLimits = new Map();
|
|
51
|
+
_contextAuthRules = [];
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
this._options = options;
|
|
54
|
+
this._app = createApp();
|
|
55
|
+
this._router = createRouter();
|
|
56
|
+
this._isDev = options.isDev ?? true;
|
|
57
|
+
this._port = options.port ?? 9000;
|
|
58
|
+
this._host = options.host ?? '0.0.0.0';
|
|
59
|
+
this._allowedOrigins = options.allowedOrigins;
|
|
60
|
+
this._startedAt = Date.now();
|
|
61
|
+
this._sessionVerifier = options.sessionVerifier ?? null;
|
|
62
|
+
this._registerHealthRoutes();
|
|
63
|
+
this._app.use(this._router);
|
|
64
|
+
}
|
|
65
|
+
/** Expose the underlying H3 App for embedding in hosts (e.g. Nitro). */
|
|
66
|
+
getApp() {
|
|
67
|
+
return this._app;
|
|
68
|
+
}
|
|
69
|
+
setAuthVerifier(verifier) {
|
|
70
|
+
this._authVerifier = verifier;
|
|
71
|
+
}
|
|
72
|
+
setSessionVerifier(verifier) {
|
|
73
|
+
this._sessionVerifier = verifier;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Register per-context auth rules (from defineUser).
|
|
77
|
+
* Paths under /api/{ctx}/ will require JWT with matching actor_type,
|
|
78
|
+
* except for public paths (login, forgot-password, etc.).
|
|
79
|
+
*/
|
|
80
|
+
registerContextAuth(contextName, actorType, publicPaths, customMiddleware) {
|
|
81
|
+
this._contextAuthRules.push({
|
|
82
|
+
prefix: `/api/${contextName}/`,
|
|
83
|
+
actorType,
|
|
84
|
+
publicPaths: new Set(publicPaths),
|
|
85
|
+
customMiddleware,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
enableRbac(enabled) {
|
|
89
|
+
this._rbacEnabled = enabled;
|
|
90
|
+
}
|
|
91
|
+
registerRoute(method, path, handler, options) {
|
|
92
|
+
const h3Handler = defineEventHandler(async (event) => {
|
|
93
|
+
return this._runPipeline(event, handler, options);
|
|
94
|
+
});
|
|
95
|
+
const m = method.toLowerCase();
|
|
96
|
+
switch (m) {
|
|
97
|
+
case 'get':
|
|
98
|
+
this._router.get(path, h3Handler);
|
|
99
|
+
break;
|
|
100
|
+
case 'post':
|
|
101
|
+
this._router.post(path, h3Handler);
|
|
102
|
+
break;
|
|
103
|
+
case 'put':
|
|
104
|
+
this._router.put(path, h3Handler);
|
|
105
|
+
break;
|
|
106
|
+
case 'delete':
|
|
107
|
+
this._router.delete(path, h3Handler);
|
|
108
|
+
break;
|
|
109
|
+
case 'patch':
|
|
110
|
+
this._router.patch(path, h3Handler);
|
|
111
|
+
break;
|
|
112
|
+
case 'options':
|
|
113
|
+
this._router.options(path, h3Handler);
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
this._router.get(path, h3Handler);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
// Also store in internal registry for handleRequest()
|
|
120
|
+
this._registerInternalRoute(method, path, handler, options);
|
|
121
|
+
}
|
|
122
|
+
async handleRequest(req) {
|
|
123
|
+
const url = new URL(req.url, 'http://localhost');
|
|
124
|
+
const method = req.method.toUpperCase();
|
|
125
|
+
const path = url.pathname;
|
|
126
|
+
const healthResponse = this._handleHealthRequest(method, path);
|
|
127
|
+
if (healthResponse)
|
|
128
|
+
return await healthResponse;
|
|
129
|
+
return this._internalHandleRequest(req);
|
|
130
|
+
}
|
|
131
|
+
async listen() {
|
|
132
|
+
const { createServer } = await import('node:http');
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
this._server = createServer(toNodeListener(this._app));
|
|
135
|
+
this._server.listen(this._port, this._host, () => {
|
|
136
|
+
resolve();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async close() {
|
|
141
|
+
if (this._server) {
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
this._server.close((err) => {
|
|
144
|
+
if (err)
|
|
145
|
+
reject(err);
|
|
146
|
+
else
|
|
147
|
+
resolve();
|
|
148
|
+
});
|
|
149
|
+
this._server = null;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
get port() {
|
|
154
|
+
return this._port;
|
|
155
|
+
}
|
|
156
|
+
// The 12-step pipeline (SPEC-039)
|
|
157
|
+
async _runPipeline(event, handler, options) {
|
|
158
|
+
try {
|
|
159
|
+
// Step 1 -- RequestID
|
|
160
|
+
const requestId = extractRequestId(event);
|
|
161
|
+
setResponseHeader(event, 'x-request-id', requestId);
|
|
162
|
+
// Step 1.5 -- Security headers
|
|
163
|
+
setSecurityHeaders(event);
|
|
164
|
+
// Step 2 -- CORS
|
|
165
|
+
const url = event.path ?? '/';
|
|
166
|
+
setCorsHeaders(event, url, this._allowedOrigins);
|
|
167
|
+
// OPTIONS preflight
|
|
168
|
+
if (getMethod(event) === 'OPTIONS') {
|
|
169
|
+
setResponseStatus(event, 204);
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
// Step 3 -- Rate limit (SPEC-039b)
|
|
173
|
+
if (this._options?.rateLimit?.enabled) {
|
|
174
|
+
const ip = getRequestHeader(event, 'x-forwarded-for') ?? getRequestHeader(event, 'x-real-ip') ?? 'unknown';
|
|
175
|
+
const { allowed, remaining, resetAt } = this._checkRateLimit(ip);
|
|
176
|
+
setResponseHeader(event, 'X-RateLimit-Remaining', String(remaining));
|
|
177
|
+
setResponseHeader(event, 'X-RateLimit-Reset', String(Math.ceil(resetAt / 1000)));
|
|
178
|
+
if (!allowed) {
|
|
179
|
+
setResponseStatus(event, 429);
|
|
180
|
+
return JSON.stringify({ type: 'RESOURCE_EXHAUSTED', message: 'Too many requests' });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Step 4 -- Scope (no-op)
|
|
184
|
+
// Step 5 -- Body parsing
|
|
185
|
+
let body = await parseBody(event);
|
|
186
|
+
// Step 6 -- Auth
|
|
187
|
+
let authContext = null;
|
|
188
|
+
if (this._authVerifier) {
|
|
189
|
+
authContext = await this._runAuthStep(event, url);
|
|
190
|
+
}
|
|
191
|
+
// Step 7 -- Publishable key (no-op)
|
|
192
|
+
// Step 8 -- Validation
|
|
193
|
+
if (options?.bodySchema && body !== undefined) {
|
|
194
|
+
body = this._runValidationStep(body, options.bodySchema);
|
|
195
|
+
}
|
|
196
|
+
// Step 9 -- Custom middlewares (no-op)
|
|
197
|
+
// Step 10 -- RBAC
|
|
198
|
+
if (this._rbacEnabled) {
|
|
199
|
+
this._runRbacStep(url, authContext);
|
|
200
|
+
}
|
|
201
|
+
// Step 11 -- Handler
|
|
202
|
+
const reqUrl = new URL(event.path ?? '/', `http://${this._host}:${this._port}`);
|
|
203
|
+
const method = getMethod(event);
|
|
204
|
+
const contentType = getRequestHeader(event, 'content-type') ?? 'application/json';
|
|
205
|
+
const reqHeaders = {
|
|
206
|
+
'content-type': contentType,
|
|
207
|
+
'x-request-id': requestId,
|
|
208
|
+
};
|
|
209
|
+
// Forward user-agent for proxy routes (PostHog, etc.)
|
|
210
|
+
const ua = getRequestHeader(event, 'user-agent');
|
|
211
|
+
if (ua)
|
|
212
|
+
reqHeaders['user-agent'] = ua;
|
|
213
|
+
const reqInit = {
|
|
214
|
+
method,
|
|
215
|
+
headers: reqHeaders,
|
|
216
|
+
};
|
|
217
|
+
// Include parsed body for CQRS routes (proxy routes bypass this pipeline entirely)
|
|
218
|
+
if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && body !== undefined) {
|
|
219
|
+
reqInit.body = JSON.stringify(body);
|
|
220
|
+
}
|
|
221
|
+
const request = new Request(reqUrl.toString(), reqInit);
|
|
222
|
+
Object.defineProperty(request, 'validatedBody', { value: body, enumerable: true });
|
|
223
|
+
Object.defineProperty(request, 'requestId', { value: requestId, enumerable: true });
|
|
224
|
+
if (authContext) {
|
|
225
|
+
Object.defineProperty(request, 'authContext', { value: authContext, enumerable: true });
|
|
226
|
+
}
|
|
227
|
+
const response = await handler(request);
|
|
228
|
+
// Step 12 -- Send response
|
|
229
|
+
setResponseStatus(event, response.status);
|
|
230
|
+
response.headers.forEach((value, key) => {
|
|
231
|
+
setResponseHeader(event, key, value);
|
|
232
|
+
});
|
|
233
|
+
setResponseHeader(event, 'content-type', response.headers.get('content-type') ?? 'application/json');
|
|
234
|
+
// HEAD requests: return headers but no body (HTTP spec)
|
|
235
|
+
if (getMethod(event) === 'HEAD') {
|
|
236
|
+
return '';
|
|
237
|
+
}
|
|
238
|
+
const responseBody = await response.text();
|
|
239
|
+
return responseBody;
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
// Step 12 -- Error handler
|
|
243
|
+
const { status, body } = mapErrorToResponse(error, this._isDev);
|
|
244
|
+
setResponseStatus(event, status);
|
|
245
|
+
setResponseHeader(event, 'content-type', 'application/json');
|
|
246
|
+
return JSON.stringify(body);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Step 3 -- Rate limiting (SPEC-039b)
|
|
250
|
+
_checkRateLimit(ip) {
|
|
251
|
+
const now = Date.now();
|
|
252
|
+
const windowMs = this._options?.rateLimit?.windowMs ?? 60000;
|
|
253
|
+
const max = this._options?.rateLimit?.maxRequests ?? 100;
|
|
254
|
+
const entry = this._rateLimits.get(ip);
|
|
255
|
+
if (!entry || now >= entry.resetAt) {
|
|
256
|
+
this._rateLimits.set(ip, { count: 1, resetAt: now + windowMs });
|
|
257
|
+
return { allowed: true, remaining: max - 1, resetAt: now + windowMs };
|
|
258
|
+
}
|
|
259
|
+
entry.count++;
|
|
260
|
+
if (entry.count > max) {
|
|
261
|
+
return { allowed: false, remaining: 0, resetAt: entry.resetAt };
|
|
262
|
+
}
|
|
263
|
+
return { allowed: true, remaining: max - entry.count, resetAt: entry.resetAt };
|
|
264
|
+
}
|
|
265
|
+
// Step 6 -- Auth: verify Bearer token, API key, or cookie session
|
|
266
|
+
async _runAuthStep(event, path) {
|
|
267
|
+
let authContext = null;
|
|
268
|
+
// 1. Bearer token
|
|
269
|
+
const authHeader = getRequestHeader(event, 'authorization');
|
|
270
|
+
const token = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null;
|
|
271
|
+
if (token && this._authVerifier) {
|
|
272
|
+
authContext = await this._authVerifier(token);
|
|
273
|
+
}
|
|
274
|
+
// 2. API key (x-api-key header)
|
|
275
|
+
if (!authContext) {
|
|
276
|
+
const apiKey = getRequestHeader(event, 'x-api-key');
|
|
277
|
+
if (apiKey && this._authVerifier) {
|
|
278
|
+
authContext = await this._authVerifier(apiKey);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// 3. Cookie session (manta.sid or session cookie)
|
|
282
|
+
if (!authContext) {
|
|
283
|
+
const cookieHeader = getRequestHeader(event, 'cookie');
|
|
284
|
+
if (cookieHeader && this._sessionVerifier) {
|
|
285
|
+
const cookies = parseCookies(cookieHeader);
|
|
286
|
+
const sessionId = cookies['manta.sid'] ?? cookies.session;
|
|
287
|
+
if (sessionId) {
|
|
288
|
+
authContext = await this._sessionVerifier(sessionId);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (requiresAuthentication(path, this._contextAuthRules) && !authContext && this._authVerifier) {
|
|
293
|
+
throw new MantaError('UNAUTHORIZED', 'Authentication required');
|
|
294
|
+
}
|
|
295
|
+
// V2: verify actor_type matches the context (or delegate to custom middleware)
|
|
296
|
+
if (this._contextAuthRules.length > 0) {
|
|
297
|
+
for (const rule of this._contextAuthRules) {
|
|
298
|
+
if (path.startsWith(rule.prefix) && !isContextPublicPath(path, rule)) {
|
|
299
|
+
if (rule.customMiddleware) {
|
|
300
|
+
// Custom middleware replaces the default actor_type check
|
|
301
|
+
const headers = {};
|
|
302
|
+
for (const [k, v] of new Request(path).headers)
|
|
303
|
+
headers[k] = v;
|
|
304
|
+
// Extract actual headers from event
|
|
305
|
+
const rawHeaders = event.headers ?? event.node?.req?.headers;
|
|
306
|
+
if (rawHeaders)
|
|
307
|
+
Object.assign(headers, rawHeaders);
|
|
308
|
+
authContext = await rule.customMiddleware({ method: getMethod(event), url: path, headers }, authContext);
|
|
309
|
+
}
|
|
310
|
+
else if (authContext && authContext.type !== rule.actorType) {
|
|
311
|
+
throw new MantaError('FORBIDDEN', `Actor type "${authContext.type}" cannot access ${rule.prefix} (requires "${rule.actorType}")`);
|
|
312
|
+
}
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return authContext;
|
|
318
|
+
}
|
|
319
|
+
// Step 8 -- Validation
|
|
320
|
+
_runValidationStep(body, schema) {
|
|
321
|
+
try {
|
|
322
|
+
return schema.parse(body);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
const issues = err.issues ?? [];
|
|
326
|
+
const details = issues.map((i) => ({ path: i.path.join('.'), message: i.message }));
|
|
327
|
+
const detail = details.map((d) => `${d.path}: ${d.message}`).join(', ');
|
|
328
|
+
throw new MantaError('INVALID_DATA', detail ? `Validation failed: ${detail}` : 'Validation failed');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Step 10 -- RBAC (basic namespace check)
|
|
332
|
+
_runRbacStep(path, authContext) {
|
|
333
|
+
// Basic RBAC: admin routes require authenticated actor
|
|
334
|
+
// More advanced RBAC (role checks) would be implemented later
|
|
335
|
+
if (path.startsWith('/api/admin') && !authContext && this._rbacEnabled) {
|
|
336
|
+
throw new MantaError('FORBIDDEN', 'Access denied');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Health endpoints -- SPEC-072 / BC-F22
|
|
340
|
+
_registerHealthRoutes() {
|
|
341
|
+
this._app.use('/health/live', defineEventHandler(() => {
|
|
342
|
+
return {
|
|
343
|
+
status: 'alive',
|
|
344
|
+
uptime_ms: Date.now() - this._startedAt,
|
|
345
|
+
};
|
|
346
|
+
}));
|
|
347
|
+
this._app.use('/health/ready', defineEventHandler(async (event) => {
|
|
348
|
+
const { status, body } = await this._computeReadiness();
|
|
349
|
+
setResponseStatus(event, status);
|
|
350
|
+
return body;
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
_handleHealthRequest(method, path) {
|
|
354
|
+
if (method !== 'GET')
|
|
355
|
+
return null;
|
|
356
|
+
if (path === '/health/live') {
|
|
357
|
+
return Response.json({
|
|
358
|
+
status: 'alive',
|
|
359
|
+
uptime_ms: Date.now() - this._startedAt,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (path === '/health/ready') {
|
|
363
|
+
return this._computeReadiness().then(({ status, body }) => Response.json(body, { status }));
|
|
364
|
+
}
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* BC-F22 — Run all configured readiness probes with a per-probe timeout.
|
|
369
|
+
* Absent probes are simply omitted from the checks object (never reported
|
|
370
|
+
* as failures). Returns HTTP 200 when every probe passes, 503 otherwise.
|
|
371
|
+
*/
|
|
372
|
+
async _computeReadiness() {
|
|
373
|
+
const probes = this._options?.readinessProbes ?? {};
|
|
374
|
+
const timeoutMs = this._options?.readinessTimeoutMs ?? 500;
|
|
375
|
+
const checks = {};
|
|
376
|
+
const entries = Object.entries(probes);
|
|
377
|
+
await Promise.all(entries.map(async ([name, probe]) => {
|
|
378
|
+
try {
|
|
379
|
+
const result = await Promise.race([
|
|
380
|
+
probe(),
|
|
381
|
+
new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs)),
|
|
382
|
+
]);
|
|
383
|
+
checks[name] = result === true ? 'ok' : 'error';
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
checks[name] = 'error';
|
|
387
|
+
}
|
|
388
|
+
}));
|
|
389
|
+
const allOk = Object.values(checks).every((v) => v === 'ok');
|
|
390
|
+
return {
|
|
391
|
+
status: allOk ? 200 : 503,
|
|
392
|
+
body: {
|
|
393
|
+
status: allOk ? 'ready' : 'not_ready',
|
|
394
|
+
uptime_ms: Date.now() - this._startedAt,
|
|
395
|
+
checks,
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
// Internal route registry for handleRequest() (testing)
|
|
400
|
+
_internalRoutes = [];
|
|
401
|
+
_registerInternalRoute(method, path, handler, options) {
|
|
402
|
+
const paramNames = [];
|
|
403
|
+
// Convert an H3-style path to a regex. Supports:
|
|
404
|
+
// :param — single segment param (captured, named)
|
|
405
|
+
// ** — catch-all wildcard matching the rest of the path (unnamed)
|
|
406
|
+
// **:name — catch-all wildcard with a capture name
|
|
407
|
+
// `**` must be escaped first — before the regex engine sees `*` as a quantifier —
|
|
408
|
+
// otherwise paths like '/api/posthog/**' throw "Nothing to repeat".
|
|
409
|
+
const regexStr = path
|
|
410
|
+
// Catch-all with named capture: **:path → ([^]*) and remember the name
|
|
411
|
+
.replace(/\*\*:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_match, name) => {
|
|
412
|
+
paramNames.push(name);
|
|
413
|
+
return '([^]*)';
|
|
414
|
+
})
|
|
415
|
+
// Bare catch-all: ** → .*
|
|
416
|
+
.replace(/\*\*/g, '.*')
|
|
417
|
+
// Single segment param: :name → ([^/]+)
|
|
418
|
+
.replace(/:([^/]+)/g, (_match, paramName) => {
|
|
419
|
+
paramNames.push(paramName);
|
|
420
|
+
return '([^/]+)';
|
|
421
|
+
});
|
|
422
|
+
this._internalRoutes.push({
|
|
423
|
+
method: method.toUpperCase(),
|
|
424
|
+
pattern: new RegExp(`^${regexStr}$`),
|
|
425
|
+
paramNames,
|
|
426
|
+
handler,
|
|
427
|
+
options,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
async _internalHandleRequest(req) {
|
|
431
|
+
const url = new URL(req.url, 'http://localhost');
|
|
432
|
+
const method = req.method.toUpperCase();
|
|
433
|
+
const pathname = url.pathname;
|
|
434
|
+
for (const route of this._internalRoutes) {
|
|
435
|
+
if (route.method !== method)
|
|
436
|
+
continue;
|
|
437
|
+
const match = pathname.match(route.pattern);
|
|
438
|
+
if (match) {
|
|
439
|
+
try {
|
|
440
|
+
// Run pipeline steps on the request
|
|
441
|
+
const requestId = req.headers.get('x-request-id') ?? crypto.randomUUID();
|
|
442
|
+
// Step 5 -- Body parsing
|
|
443
|
+
let body;
|
|
444
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
445
|
+
body = await req
|
|
446
|
+
.clone()
|
|
447
|
+
.json()
|
|
448
|
+
.catch(() => undefined);
|
|
449
|
+
}
|
|
450
|
+
// Step 6 -- Auth (Bearer, API key, cookie)
|
|
451
|
+
let authContext = null;
|
|
452
|
+
// 1. Bearer token
|
|
453
|
+
if (this._authVerifier) {
|
|
454
|
+
const authHeader = req.headers.get('authorization');
|
|
455
|
+
const token = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null;
|
|
456
|
+
if (token) {
|
|
457
|
+
authContext = await this._authVerifier(token);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// 2. API key
|
|
461
|
+
if (!authContext && this._authVerifier) {
|
|
462
|
+
const apiKey = req.headers.get('x-api-key');
|
|
463
|
+
if (apiKey) {
|
|
464
|
+
authContext = await this._authVerifier(apiKey);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// 3. Cookie session
|
|
468
|
+
if (!authContext && this._sessionVerifier) {
|
|
469
|
+
const cookieHeader = req.headers.get('cookie');
|
|
470
|
+
if (cookieHeader) {
|
|
471
|
+
const cookies = parseCookies(cookieHeader);
|
|
472
|
+
const sessionId = cookies['manta.sid'] ?? cookies.session;
|
|
473
|
+
if (sessionId) {
|
|
474
|
+
authContext = await this._sessionVerifier(sessionId);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if ((this._authVerifier || this._sessionVerifier) &&
|
|
479
|
+
requiresAuthentication(pathname, this._contextAuthRules) &&
|
|
480
|
+
!authContext) {
|
|
481
|
+
throw new MantaError('UNAUTHORIZED', 'Authentication required');
|
|
482
|
+
}
|
|
483
|
+
// V2: verify actor_type matches context (or delegate to custom middleware)
|
|
484
|
+
if (this._contextAuthRules.length > 0) {
|
|
485
|
+
for (const rule of this._contextAuthRules) {
|
|
486
|
+
if (pathname.startsWith(rule.prefix) && !isContextPublicPath(pathname, rule)) {
|
|
487
|
+
if (rule.customMiddleware) {
|
|
488
|
+
const headers = {};
|
|
489
|
+
for (const [k, v] of req.headers)
|
|
490
|
+
headers[k] = v;
|
|
491
|
+
authContext = await rule.customMiddleware({ method, url: pathname, headers }, authContext);
|
|
492
|
+
}
|
|
493
|
+
else if (authContext && authContext.type !== rule.actorType) {
|
|
494
|
+
throw new MantaError('FORBIDDEN', `Actor type "${authContext.type}" cannot access ${rule.prefix}`);
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// Step 8 -- Validation
|
|
501
|
+
if (route.options?.bodySchema && body !== undefined) {
|
|
502
|
+
try {
|
|
503
|
+
body = route.options.bodySchema.parse(body);
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
const issues = err.issues ?? [];
|
|
507
|
+
const details = issues.map((i) => ({ path: i.path.join('.'), message: i.message }));
|
|
508
|
+
const detail = details.map((d) => `${d.path}: ${d.message}`).join(', ');
|
|
509
|
+
throw new MantaError('INVALID_DATA', detail ? `Validation failed: ${detail}` : 'Validation failed');
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// Step 10 -- RBAC
|
|
513
|
+
if (this._rbacEnabled && pathname.startsWith('/api/admin') && !authContext) {
|
|
514
|
+
throw new MantaError('FORBIDDEN', 'Access denied');
|
|
515
|
+
}
|
|
516
|
+
// Build enriched request — clone original to preserve raw body (gzip, binary, etc.)
|
|
517
|
+
const enrichedReq = req.clone();
|
|
518
|
+
Object.defineProperty(enrichedReq, 'validatedBody', { value: body, enumerable: true });
|
|
519
|
+
Object.defineProperty(enrichedReq, 'requestId', { value: requestId, enumerable: true });
|
|
520
|
+
if (authContext) {
|
|
521
|
+
Object.defineProperty(enrichedReq, 'authContext', { value: authContext, enumerable: true });
|
|
522
|
+
}
|
|
523
|
+
// Extract params
|
|
524
|
+
const params = {};
|
|
525
|
+
for (let i = 0; i < route.paramNames.length; i++) {
|
|
526
|
+
params[route.paramNames[i]] = decodeURIComponent(match[i + 1] ?? '');
|
|
527
|
+
}
|
|
528
|
+
Object.defineProperty(enrichedReq, 'params', { value: params, enumerable: true });
|
|
529
|
+
return await route.handler(enrichedReq);
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
const { status, body } = mapErrorToResponse(error, this._isDev);
|
|
533
|
+
return new Response(JSON.stringify(body), {
|
|
534
|
+
status,
|
|
535
|
+
headers: { 'Content-Type': 'application/json' },
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return new Response(JSON.stringify({ type: 'NOT_FOUND', message: 'Route not found' }), {
|
|
541
|
+
status: 404,
|
|
542
|
+
headers: { 'Content-Type': 'application/json' },
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/** Parse a Cookie header string into key-value pairs. */
|
|
547
|
+
function parseCookies(header) {
|
|
548
|
+
const cookies = {};
|
|
549
|
+
for (const part of header.split(';')) {
|
|
550
|
+
const [key, ...rest] = part.trim().split('=');
|
|
551
|
+
if (key)
|
|
552
|
+
cookies[key.trim()] = rest.join('=').trim();
|
|
553
|
+
}
|
|
554
|
+
return cookies;
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { createApp } from 'h3';
|
|
2
|
+
type App = ReturnType<typeof createApp>;
|
|
3
|
+
import { H3Adapter } from './adapter';
|
|
4
|
+
interface DiscoveredRoute {
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
file: string;
|
|
8
|
+
exportName: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A pre-registered route handler.
|
|
12
|
+
* Use this when routes are already imported (e.g. in Nitro where bundling handles imports).
|
|
13
|
+
*/
|
|
14
|
+
export interface RouteHandler {
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
handler: (req: unknown) => Promise<Response> | Response;
|
|
18
|
+
}
|
|
19
|
+
export interface MantaH3AppOptions {
|
|
20
|
+
/** The MantaApp instance. Used for resolve() and injected into requests as req.app. */
|
|
21
|
+
mantaApp?: {
|
|
22
|
+
resolve: <T>(key: string) => T;
|
|
23
|
+
workflows?: unknown;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
};
|
|
26
|
+
/** Working directory (for route discovery from src/api/). Omit if providing `routes`. */
|
|
27
|
+
cwd?: string;
|
|
28
|
+
/** Custom import function for .ts files (e.g. jiti). Falls back to native import(). */
|
|
29
|
+
importFn?: (path: string) => Promise<Record<string, unknown>>;
|
|
30
|
+
/** Pre-registered routes. If provided, skips filesystem discovery. */
|
|
31
|
+
routes?: RouteHandler[];
|
|
32
|
+
/** Dev mode (default: true) */
|
|
33
|
+
isDev?: boolean;
|
|
34
|
+
/** Logger (optional, for route logging) */
|
|
35
|
+
logger?: {
|
|
36
|
+
info: (msg: string) => void;
|
|
37
|
+
warn: (msg: string) => void;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface MantaH3App {
|
|
41
|
+
/** The H3 App, ready to be mounted on any host */
|
|
42
|
+
app: App;
|
|
43
|
+
/** The underlying H3Adapter instance */
|
|
44
|
+
adapter: H3Adapter;
|
|
45
|
+
/** The discovered routes */
|
|
46
|
+
routes: DiscoveredRoute[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates a fully configured Manta H3 app.
|
|
50
|
+
*
|
|
51
|
+
* This is the main entry point for adapter-h3. It:
|
|
52
|
+
* 1. Creates an H3Adapter
|
|
53
|
+
* 2. Discovers routes from src/api/
|
|
54
|
+
* 3. Registers them on the adapter with scope injection
|
|
55
|
+
* 4. Returns the H3 App ready to be mounted on any host (Nitro, standalone, etc.)
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* const app = appBuilder.build()
|
|
59
|
+
* const { app: h3App } = await createMantaH3App({
|
|
60
|
+
* mantaApp: app,
|
|
61
|
+
* cwd,
|
|
62
|
+
* })
|
|
63
|
+
* // Mount h3App on Nitro, or listen directly
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function createMantaH3App(options: MantaH3AppOptions): Promise<MantaH3App>;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAEnC,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAIrC,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAmDD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;CACxD;AAED,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;IAC1F,yFAAyF;IACzF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,uFAAuF;IACvF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC7D,sEAAsE;IACtE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,2CAA2C;IAC3C,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAA;CACtE;AAED,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,GAAG,EAAE,GAAG,CAAA;IACR,wCAAwC;IACxC,OAAO,EAAE,SAAS,CAAA;IAClB,4BAA4B;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmGtF"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// SPEC-039 — H3 App factory
|
|
2
|
+
// Takes a bootstrapped Manta app, discovers routes, creates and returns the H3 app.
|
|
3
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
|
+
import { dirname, relative, resolve } from 'node:path';
|
|
5
|
+
import { H3Adapter } from './adapter';
|
|
6
|
+
const HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']);
|
|
7
|
+
function findRouteFiles(dir) {
|
|
8
|
+
const files = [];
|
|
9
|
+
if (!existsSync(dir))
|
|
10
|
+
return files;
|
|
11
|
+
for (const entry of readdirSync(dir)) {
|
|
12
|
+
const fullPath = resolve(dir, entry);
|
|
13
|
+
if (statSync(fullPath).isDirectory()) {
|
|
14
|
+
files.push(...findRouteFiles(fullPath));
|
|
15
|
+
}
|
|
16
|
+
else if (entry === 'route.ts' || entry === 'route.js') {
|
|
17
|
+
files.push(fullPath);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return files;
|
|
21
|
+
}
|
|
22
|
+
async function discoverRoutes(cwd, importFn) {
|
|
23
|
+
const apiDir = resolve(cwd, 'src', 'api');
|
|
24
|
+
if (!existsSync(apiDir))
|
|
25
|
+
return [];
|
|
26
|
+
const routeFiles = findRouteFiles(apiDir);
|
|
27
|
+
const routes = [];
|
|
28
|
+
const doImport = importFn ?? ((path) => import(`${path}?t=${Date.now()}`));
|
|
29
|
+
for (const file of routeFiles) {
|
|
30
|
+
const relPath = relative(apiDir, dirname(file));
|
|
31
|
+
const urlPath = '/api/' +
|
|
32
|
+
relPath
|
|
33
|
+
.split('/')
|
|
34
|
+
.map((seg) => (seg.startsWith('[') && seg.endsWith(']') ? `:${seg.slice(1, -1)}` : seg))
|
|
35
|
+
.join('/');
|
|
36
|
+
const mod = await doImport(file);
|
|
37
|
+
for (const exportName of Object.keys(mod)) {
|
|
38
|
+
if (HTTP_METHODS.has(exportName) && typeof mod[exportName] === 'function') {
|
|
39
|
+
routes.push({ method: exportName, path: urlPath, file, exportName });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return routes;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a fully configured Manta H3 app.
|
|
47
|
+
*
|
|
48
|
+
* This is the main entry point for adapter-h3. It:
|
|
49
|
+
* 1. Creates an H3Adapter
|
|
50
|
+
* 2. Discovers routes from src/api/
|
|
51
|
+
* 3. Registers them on the adapter with scope injection
|
|
52
|
+
* 4. Returns the H3 App ready to be mounted on any host (Nitro, standalone, etc.)
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* const app = appBuilder.build()
|
|
56
|
+
* const { app: h3App } = await createMantaH3App({
|
|
57
|
+
* mantaApp: app,
|
|
58
|
+
* cwd,
|
|
59
|
+
* })
|
|
60
|
+
* // Mount h3App on Nitro, or listen directly
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export async function createMantaH3App(options) {
|
|
64
|
+
const { mantaApp, cwd, isDev = true, logger } = options;
|
|
65
|
+
if (!mantaApp)
|
|
66
|
+
throw new Error('createMantaH3App requires mantaApp');
|
|
67
|
+
const adapter = new H3Adapter({ port: 0, isDev });
|
|
68
|
+
const scope = { resolve: (key) => mantaApp.resolve(key) };
|
|
69
|
+
// Either use pre-registered routes or discover from filesystem
|
|
70
|
+
const routeHandlers = [];
|
|
71
|
+
if (options.routes) {
|
|
72
|
+
// Pre-registered routes (e.g. from a Nitro plugin where modules are already bundled)
|
|
73
|
+
routeHandlers.push(...options.routes);
|
|
74
|
+
}
|
|
75
|
+
else if (cwd) {
|
|
76
|
+
// Discover routes from filesystem (standalone mode / CLI)
|
|
77
|
+
const doImport = options.importFn ?? ((path) => import(`${path}?t=${Date.now()}`));
|
|
78
|
+
const discovered = await discoverRoutes(cwd, doImport);
|
|
79
|
+
for (const route of discovered) {
|
|
80
|
+
const mod = await doImport(route.file);
|
|
81
|
+
const handlerFn = mod[route.exportName];
|
|
82
|
+
routeHandlers.push({ method: route.method, path: route.path, handler: handlerFn });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Register all routes on the H3Adapter
|
|
86
|
+
for (const route of routeHandlers) {
|
|
87
|
+
adapter.registerRoute(route.method, route.path, async (req) => {
|
|
88
|
+
// Enrich the request with MantaApp, scope, query, workflows, params, validatedBody
|
|
89
|
+
const mantaReq = req;
|
|
90
|
+
// Enrich request — only set properties not already defined by the pipeline
|
|
91
|
+
if (!('scope' in mantaReq)) {
|
|
92
|
+
Object.defineProperty(mantaReq, 'scope', { value: scope, enumerable: true, configurable: true });
|
|
93
|
+
}
|
|
94
|
+
// Inject MantaApp if provided
|
|
95
|
+
if (options.mantaApp && !('app' in mantaReq)) {
|
|
96
|
+
Object.defineProperty(mantaReq, 'app', { value: options.mantaApp, enumerable: true, configurable: true });
|
|
97
|
+
}
|
|
98
|
+
// Inject shortcuts: req.query and req.workflows
|
|
99
|
+
if (options.mantaApp) {
|
|
100
|
+
if (!('query' in mantaReq)) {
|
|
101
|
+
try {
|
|
102
|
+
const queryService = options.mantaApp.resolve('query');
|
|
103
|
+
Object.defineProperty(mantaReq, 'query', { value: queryService, enumerable: true, configurable: true });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// query service not registered — skip
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!('workflows' in mantaReq)) {
|
|
110
|
+
Object.defineProperty(mantaReq, 'workflows', {
|
|
111
|
+
value: options.mantaApp.workflows,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Extract path params (only if not already set)
|
|
118
|
+
if (!('params' in mantaReq)) {
|
|
119
|
+
const patternParts = route.path.split('/');
|
|
120
|
+
const pathParts = new URL(req.url).pathname.split('/');
|
|
121
|
+
const params = {};
|
|
122
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
123
|
+
if (patternParts[i].startsWith(':')) {
|
|
124
|
+
params[patternParts[i].slice(1)] = pathParts[i] ?? '';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
Object.defineProperty(mantaReq, 'params', { value: params, enumerable: true, configurable: true });
|
|
128
|
+
}
|
|
129
|
+
// Parse body for mutation methods (only if not already set)
|
|
130
|
+
if (!('validatedBody' in mantaReq) && ['POST', 'PUT', 'PATCH'].includes(route.method)) {
|
|
131
|
+
try {
|
|
132
|
+
const rawBody = await req
|
|
133
|
+
.clone()
|
|
134
|
+
.json()
|
|
135
|
+
.catch(() => ({}));
|
|
136
|
+
Object.defineProperty(mantaReq, 'validatedBody', { value: rawBody, enumerable: true, configurable: true });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
Object.defineProperty(mantaReq, 'validatedBody', { value: {}, enumerable: true, configurable: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return route.handler(mantaReq);
|
|
143
|
+
});
|
|
144
|
+
logger?.info(` ${route.method} ${route.path}`);
|
|
145
|
+
}
|
|
146
|
+
if (routeHandlers.length === 0)
|
|
147
|
+
logger?.warn('No routes registered');
|
|
148
|
+
return { app: adapter.getApp(), adapter, routes: routeHandlers.map((r) => ({ ...r, file: '', exportName: '' })) };
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,oFAAoF;AAEpF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKtD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAWrC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;AAEvE,SAAS,cAAc,CAAC,GAAW;IACjC,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IAClC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACpC,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAA;QACzC,CAAC;aAAM,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,GAAW,EACX,QAA6D;IAE7D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;IACzC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;IACzC,MAAM,MAAM,GAAsB,EAAE,CAAA;IAEpC,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;IAElF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QAC/C,MAAM,OAAO,GACX,OAAO;YACP,OAAO;iBACJ,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;iBACvF,IAAI,CAAC,GAAG,CAAC,CAAA;QAEd,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAA;QAChC,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,OAAO,GAAG,CAAC,UAAU,CAAC,KAAK,UAAU,EAAE,CAAC;gBAC1E,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;YACtE,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAsCD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAA0B;IAC/D,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAEvD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IAEpE,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IACjD,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,CAAI,GAAW,EAAK,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAI,GAAG,CAAC,EAAE,CAAA;IAE1E,+DAA+D;IAC/D,MAAM,aAAa,GAId,EAAE,CAAA;IAEP,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,qFAAqF;QACrF,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC;SAAM,IAAI,GAAG,EAAE,CAAC;QACf,0DAA0D;QAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1F,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QACtD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAmD,CAAA;YACzF,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QACpF,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;YACrE,mFAAmF;YACnF,MAAM,QAAQ,GAAsC,GAAwC,CAAA;YAE5F,2EAA2E;YAC3E,IAAI,CAAC,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,CAAC;gBAC3B,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;YAClG,CAAC;YAED,8BAA8B;YAC9B,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC,EAAE,CAAC;gBAC7C,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;YAC3G,CAAC;YAED,gDAAgD;YAChD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,IAAI,CAAC,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,CAAC;oBAC3B,IAAI,CAAC;wBACH,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;wBACtD,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;oBACzG,CAAC;oBAAC,MAAM,CAAC;wBACP,sCAAsC;oBACxC,CAAC;gBACH,CAAC;gBACD,IAAI,CAAC,CAAC,WAAW,IAAI,QAAQ,CAAC,EAAE,CAAC;oBAC/B,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE;wBAC3C,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;wBACjC,UAAU,EAAE,IAAI;wBAChB,YAAY,EAAE,IAAI;qBACnB,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAED,gDAAgD;YAChD,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;gBAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBACtD,MAAM,MAAM,GAA2B,EAAE,CAAA;gBACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7C,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;wBACpC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;oBACvD,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;YACpG,CAAC;YAED,4DAA4D;YAC5D,IAAI,CAAC,CAAC,eAAe,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtF,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,GAAG;yBACtB,KAAK,EAAE;yBACP,IAAI,EAAE;yBACN,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;oBACpB,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC5G,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;gBACvG,CAAC;YACH,CAAC;YAED,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;QAEF,MAAM,EAAE,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACjD,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAEpE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAA;AACnH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EventHandler } from 'h3';
|
|
2
|
+
export interface MantaHandlerOptions {
|
|
3
|
+
isDev?: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Creates an H3 event handler that runs a Manta route handler
|
|
7
|
+
* through the pipeline.
|
|
8
|
+
*
|
|
9
|
+
* Usage in an H3 app:
|
|
10
|
+
* ```ts
|
|
11
|
+
* app.use('/admin/products', createMantaH3Handler(async (req) => {
|
|
12
|
+
* // ... your handler
|
|
13
|
+
* return Response.json({ products })
|
|
14
|
+
* }))
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function createMantaH3Handler(handler: (req: Request) => Promise<Response> | Response, options?: MantaHandlerOptions): EventHandler;
|
|
18
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,IAAI,CAAA;AAI/C,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,EACvD,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CAmDd"}
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// SPEC-039 — createMantaH3Handler for H3
|
|
2
|
+
import { defineEventHandler, getMethod, readBody, setResponseHeader, setResponseStatus } from 'h3';
|
|
3
|
+
import { extractRequestId, mapErrorToResponse, setCorsHeaders } from './pipeline';
|
|
4
|
+
/**
|
|
5
|
+
* Creates an H3 event handler that runs a Manta route handler
|
|
6
|
+
* through the pipeline.
|
|
7
|
+
*
|
|
8
|
+
* Usage in an H3 app:
|
|
9
|
+
* ```ts
|
|
10
|
+
* app.use('/admin/products', createMantaH3Handler(async (req) => {
|
|
11
|
+
* // ... your handler
|
|
12
|
+
* return Response.json({ products })
|
|
13
|
+
* }))
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function createMantaH3Handler(handler, options) {
|
|
17
|
+
const isDev = options?.isDev ?? true;
|
|
18
|
+
return defineEventHandler(async (event) => {
|
|
19
|
+
try {
|
|
20
|
+
// Step 1 — RequestID
|
|
21
|
+
const requestId = extractRequestId(event);
|
|
22
|
+
setResponseHeader(event, 'x-request-id', requestId);
|
|
23
|
+
// Step 2 — CORS
|
|
24
|
+
setCorsHeaders(event, event.path ?? '/');
|
|
25
|
+
// Step 5 — Body
|
|
26
|
+
const method = getMethod(event);
|
|
27
|
+
let body;
|
|
28
|
+
if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {
|
|
29
|
+
try {
|
|
30
|
+
body = await readBody(event);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* empty body */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Build request for handler
|
|
37
|
+
const url = `http://localhost${event.path ?? '/'}`;
|
|
38
|
+
const request = new Request(url, {
|
|
39
|
+
method,
|
|
40
|
+
headers: { 'content-type': 'application/json', 'x-request-id': requestId },
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(request, 'validatedBody', { value: body, enumerable: true });
|
|
43
|
+
Object.defineProperty(request, 'requestId', { value: requestId, enumerable: true });
|
|
44
|
+
// Step 11 — Handler
|
|
45
|
+
const response = await handler(request);
|
|
46
|
+
// Send response
|
|
47
|
+
setResponseStatus(event, response.status);
|
|
48
|
+
response.headers.forEach((value, key) => {
|
|
49
|
+
setResponseHeader(event, key, value);
|
|
50
|
+
});
|
|
51
|
+
setResponseHeader(event, 'content-type', response.headers.get('content-type') ?? 'application/json');
|
|
52
|
+
return await response.text();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Step 12 — Error handler
|
|
56
|
+
const { status, body: errBody } = mapErrorToResponse(error, isDev);
|
|
57
|
+
setResponseStatus(event, status);
|
|
58
|
+
setResponseHeader(event, 'content-type', 'application/json');
|
|
59
|
+
return JSON.stringify(errBody);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,yCAAyC;AAGzC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAA;AAClG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAMjF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAuD,EACvD,OAA6B;IAE7B,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,CAAA;IAEpC,OAAO,kBAAkB,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,qBAAqB;YACrB,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACzC,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,CAAA;YAEnD,gBAAgB;YAChB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC,CAAA;YAExC,gBAAgB;YAChB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,IAAa,CAAA;YACjB,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAClE,IAAI,CAAC;oBACH,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAC9B,CAAC;gBAAC,MAAM,CAAC;oBACP,gBAAgB;gBAClB,CAAC;YACH,CAAC;YAED,4BAA4B;YAC5B,MAAM,GAAG,GAAG,mBAAmB,KAAK,CAAC,IAAI,IAAI,GAAG,EAAE,CAAA;YAClD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;gBAC/B,MAAM;gBACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,SAAS,EAAE;aAC3E,CAAC,CAAA;YACF,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;YAClF,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;YAEnF,oBAAoB;YACpB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;YAEvC,gBAAgB;YAChB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;YACzC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACtC,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;YACtC,CAAC,CAAC,CAAA;YACF,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC,CAAA;YAEpG,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,0BAA0B;YAC1B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YAClE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAChC,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAA;YAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QAChC,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { defineEventHandler, getRequestHeaders, getRequestURL, readRawBody, setResponseHeader } from 'h3';
|
|
2
|
+
/** @deprecated Use H3AdapterOptions */
|
|
3
|
+
export type { AuthContext, AuthVerifier, H3AdapterOptions, H3AdapterOptions as NitroAdapterOptions, ReadinessProbe, RouteOptions, SessionVerifier, } from './adapter';
|
|
4
|
+
/** @deprecated Use H3Adapter */
|
|
5
|
+
export { H3Adapter, H3Adapter as NitroAdapter } from './adapter';
|
|
6
|
+
export type { MantaH3App, MantaH3AppOptions, RouteHandler } from './app';
|
|
7
|
+
export { createMantaH3App } from './app';
|
|
8
|
+
export type { MantaHandlerOptions } from './handler';
|
|
9
|
+
/** @deprecated Use createMantaH3Handler */
|
|
10
|
+
export { createMantaH3Handler, createMantaH3Handler as createMantaHandler } from './handler';
|
|
11
|
+
export type { ErrorResponseBody, PipelineContext } from './pipeline';
|
|
12
|
+
export { ERROR_STATUS_MAP, extractRequestId, mapErrorToResponse, parseBody, setCorsHeaders } from './pipeline';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAA;AACzG,uCAAuC;AACvC,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,IAAI,mBAAmB,EACvC,cAAc,EACd,YAAY,EACZ,eAAe,GAChB,MAAM,WAAW,CAAA;AAElB,gCAAgC;AAChC,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,WAAW,CAAA;AAChE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AACxC,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,2CAA2C;AAC3C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,IAAI,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC5F,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPEC-039 — @mantajs/adapter-h3 barrel export
|
|
2
|
+
export { defineEventHandler, getRequestHeaders, getRequestURL, readRawBody, setResponseHeader } from 'h3';
|
|
3
|
+
// Compat aliases — deprecated
|
|
4
|
+
/** @deprecated Use H3Adapter */
|
|
5
|
+
export { H3Adapter, H3Adapter as NitroAdapter } from './adapter';
|
|
6
|
+
export { createMantaH3App } from './app';
|
|
7
|
+
/** @deprecated Use createMantaH3Handler */
|
|
8
|
+
export { createMantaH3Handler, createMantaH3Handler as createMantaHandler } from './handler';
|
|
9
|
+
export { ERROR_STATUS_MAP, extractRequestId, mapErrorToResponse, parseBody, setCorsHeaders } from './pipeline';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAA;AAWzG,8BAA8B;AAC9B,gCAAgC;AAChC,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,WAAW,CAAA;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAExC,2CAA2C;AAC3C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,IAAI,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAE5F,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
/**
|
|
3
|
+
* Error status mapping — SPEC-041
|
|
4
|
+
*/
|
|
5
|
+
export declare const ERROR_STATUS_MAP: Record<string, number>;
|
|
6
|
+
/**
|
|
7
|
+
* MantaErrorResponse body format — SPEC-041
|
|
8
|
+
*/
|
|
9
|
+
export interface ErrorResponseBody {
|
|
10
|
+
type: string;
|
|
11
|
+
message: string;
|
|
12
|
+
code?: string;
|
|
13
|
+
details?: unknown;
|
|
14
|
+
stack?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface PipelineContext {
|
|
17
|
+
requestId: string;
|
|
18
|
+
method: string;
|
|
19
|
+
path: string;
|
|
20
|
+
body?: unknown;
|
|
21
|
+
params?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Step 1 — Generate or propagate x-request-id
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractRequestId(event: H3Event): string;
|
|
27
|
+
/**
|
|
28
|
+
* Step 2 — CORS headers based on namespace
|
|
29
|
+
*/
|
|
30
|
+
export declare function setCorsHeaders(event: H3Event, _path: string, allowedOrigins?: string[]): void;
|
|
31
|
+
/**
|
|
32
|
+
* Step 1.5 — Security headers (before handler runs)
|
|
33
|
+
*/
|
|
34
|
+
export declare function setSecurityHeaders(event: H3Event): void;
|
|
35
|
+
/**
|
|
36
|
+
* Step 5 — Parse body based on content-type
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseBody(event: H3Event, maxBodySize?: number): Promise<unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Step 12 — Map errors to HTTP responses
|
|
41
|
+
*/
|
|
42
|
+
export declare function mapErrorToResponse(error: unknown, isDev: boolean): {
|
|
43
|
+
status: number;
|
|
44
|
+
body: ErrorResponseBody;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAGjC;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAcnD,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAwB7F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAKvD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,SAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBvF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAuB9G"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPEC-039 — 12-step HTTP pipeline for H3
|
|
2
|
+
import { MantaError } from '@mantajs/core/errors';
|
|
3
|
+
import { getMethod, getRequestHeader, readBody, setResponseHeader } from 'h3';
|
|
4
|
+
/**
|
|
5
|
+
* Error status mapping — SPEC-041
|
|
6
|
+
*/
|
|
7
|
+
export const ERROR_STATUS_MAP = {
|
|
8
|
+
NOT_FOUND: 404,
|
|
9
|
+
INVALID_DATA: 400,
|
|
10
|
+
UNAUTHORIZED: 401,
|
|
11
|
+
FORBIDDEN: 403,
|
|
12
|
+
DUPLICATE_ERROR: 409,
|
|
13
|
+
CONFLICT: 409,
|
|
14
|
+
NOT_ALLOWED: 405,
|
|
15
|
+
UNEXPECTED_STATE: 500,
|
|
16
|
+
DB_ERROR: 500,
|
|
17
|
+
UNKNOWN_MODULES: 500,
|
|
18
|
+
INVALID_STATE: 500,
|
|
19
|
+
NOT_IMPLEMENTED: 501,
|
|
20
|
+
RESOURCE_EXHAUSTED: 429,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Step 1 — Generate or propagate x-request-id
|
|
24
|
+
*/
|
|
25
|
+
export function extractRequestId(event) {
|
|
26
|
+
const existing = getRequestHeader(event, 'x-request-id');
|
|
27
|
+
if (existing)
|
|
28
|
+
return existing;
|
|
29
|
+
return crypto.randomUUID();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Step 2 — CORS headers based on namespace
|
|
33
|
+
*/
|
|
34
|
+
export function setCorsHeaders(event, _path, allowedOrigins) {
|
|
35
|
+
const origin = getRequestHeader(event, 'origin');
|
|
36
|
+
if (!origin) {
|
|
37
|
+
// No CORS needed for same-origin requests
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// If allowedOrigins configured, validate
|
|
41
|
+
if (allowedOrigins && allowedOrigins.length > 0) {
|
|
42
|
+
if (!allowedOrigins.includes(origin) && !allowedOrigins.includes('*')) {
|
|
43
|
+
return; // Don't set CORS headers for disallowed origins
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
setResponseHeader(event, 'Access-Control-Allow-Origin', origin);
|
|
47
|
+
setResponseHeader(event, 'Access-Control-Allow-Credentials', 'true');
|
|
48
|
+
setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
|
49
|
+
setResponseHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization, x-publishable-api-key, x-request-id');
|
|
50
|
+
setResponseHeader(event, 'Access-Control-Max-Age', '86400');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Step 1.5 — Security headers (before handler runs)
|
|
54
|
+
*/
|
|
55
|
+
export function setSecurityHeaders(event) {
|
|
56
|
+
setResponseHeader(event, 'X-Content-Type-Options', 'nosniff');
|
|
57
|
+
setResponseHeader(event, 'X-Frame-Options', 'DENY');
|
|
58
|
+
setResponseHeader(event, 'X-XSS-Protection', '0');
|
|
59
|
+
setResponseHeader(event, 'Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Step 5 — Parse body based on content-type
|
|
63
|
+
*/
|
|
64
|
+
export async function parseBody(event, maxBodySize = 1048576) {
|
|
65
|
+
const method = getMethod(event);
|
|
66
|
+
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS') {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const contentLength = getRequestHeader(event, 'content-length');
|
|
70
|
+
if (contentLength && parseInt(contentLength, 10) > maxBodySize) {
|
|
71
|
+
throw new MantaError('INVALID_DATA', `Request body too large (max ${maxBodySize} bytes)`);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
return await readBody(event);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Step 12 — Map errors to HTTP responses
|
|
82
|
+
*/
|
|
83
|
+
export function mapErrorToResponse(error, isDev) {
|
|
84
|
+
if (MantaError.is(error)) {
|
|
85
|
+
const status = ERROR_STATUS_MAP[error.type] ?? 500;
|
|
86
|
+
const body = {
|
|
87
|
+
type: error.type,
|
|
88
|
+
message: error.message,
|
|
89
|
+
};
|
|
90
|
+
if (error.code)
|
|
91
|
+
body.code = error.code;
|
|
92
|
+
if (isDev && error.stack)
|
|
93
|
+
body.stack = error.stack;
|
|
94
|
+
return { status, body };
|
|
95
|
+
}
|
|
96
|
+
// Unknown error — log in dev for debugging
|
|
97
|
+
if (isDev) {
|
|
98
|
+
console.error('[pipeline] Unhandled error:', error);
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
status: 500,
|
|
102
|
+
body: {
|
|
103
|
+
type: 'UNEXPECTED_STATE',
|
|
104
|
+
message: isDev ? String(error?.message ?? error) : 'An internal error occurred',
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mantajs/adapter-h3",
|
|
3
|
+
"version": "0.2.0-beta.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"h3": "^2.0.1-rc.16",
|
|
16
|
+
"jiti": "^2.6.1"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@mantajs/core": "0.2.0-beta.0"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
]
|
|
24
|
+
}
|