@grapity/grapity 0.2.0 → 0.4.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/README.md +47 -14
- package/dist/assets/index-JAhtTTW2.js +336 -0
- package/dist/assets/index-JAhtTTW2.js.map +1 -0
- package/dist/assets/index-LDlidn22.css +1 -0
- package/dist/cli/index.js +1315 -181
- package/dist/core/index.d.ts +391 -23
- package/dist/hub/index.js +34 -7
- package/dist/hub/serve.d.ts +9 -1
- package/dist/hub/serve.js +34 -7
- package/dist/index.html +3 -2
- package/dist/registry/{index-Baj_sSgl.d.ts → index-Bx-7YlUF.d.ts} +18 -11
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +152 -6
- package/dist/registry/serve.d.ts +96 -5
- package/dist/registry/serve.js +714 -21
- package/package.json +13 -15
- package/dist/assets/index-Dq5tdnlb.js +0 -326
- package/dist/assets/index-Dq5tdnlb.js.map +0 -1
- package/dist/assets/index-NJpHAonA.css +0 -1
package/dist/hub/index.js
CHANGED
|
@@ -17,15 +17,34 @@ var DEFAULT_REGISTRY_URL = "http://localhost:3750";
|
|
|
17
17
|
async function startHubServer(userConfig) {
|
|
18
18
|
const config = {
|
|
19
19
|
port: userConfig?.port ?? DEFAULT_PORT,
|
|
20
|
-
registryUrl: userConfig?.registryUrl ?? DEFAULT_REGISTRY_URL
|
|
20
|
+
registryUrl: userConfig?.registryUrl ?? DEFAULT_REGISTRY_URL,
|
|
21
|
+
auth: userConfig?.auth
|
|
21
22
|
};
|
|
22
23
|
const app = new Hono();
|
|
24
|
+
app.get("/config.js", (c) => {
|
|
25
|
+
const clientConfig = {
|
|
26
|
+
registryUrl: config.registryUrl,
|
|
27
|
+
auth: config.auth ? {
|
|
28
|
+
mode: config.auth.mode,
|
|
29
|
+
serverUrl: config.auth.serverUrl,
|
|
30
|
+
realm: config.auth.realm,
|
|
31
|
+
clientId: config.auth.clientId,
|
|
32
|
+
audience: config.auth.audience
|
|
33
|
+
} : void 0
|
|
34
|
+
};
|
|
35
|
+
c.header("Content-Type", "application/javascript");
|
|
36
|
+
return c.body(
|
|
37
|
+
`window.__GRAPITY_CONFIG__ = ${JSON.stringify(clientConfig)};`
|
|
38
|
+
);
|
|
39
|
+
});
|
|
23
40
|
app.use("/v1/*", async (c) => {
|
|
24
41
|
const url = new URL(c.req.url);
|
|
25
42
|
const targetUrl = config.registryUrl + url.pathname + url.search;
|
|
43
|
+
const headers = new Headers(c.req.raw.headers);
|
|
44
|
+
headers.delete("host");
|
|
26
45
|
const response = await fetch(targetUrl, {
|
|
27
46
|
method: c.req.method,
|
|
28
|
-
headers
|
|
47
|
+
headers,
|
|
29
48
|
body: c.req.raw.body
|
|
30
49
|
});
|
|
31
50
|
return response;
|
|
@@ -33,13 +52,21 @@ async function startHubServer(userConfig) {
|
|
|
33
52
|
app.use("/*", serveStatic({ root: HUB_DIST_PATH }));
|
|
34
53
|
app.get("/*", async (c) => {
|
|
35
54
|
const indexPath = path.join(HUB_DIST_PATH, "index.html");
|
|
36
|
-
if (fs.existsSync(indexPath)) {
|
|
37
|
-
return c.
|
|
55
|
+
if (!fs.existsSync(indexPath)) {
|
|
56
|
+
return c.text(
|
|
57
|
+
"index.html not found. Build the project with 'bun run build' first.",
|
|
58
|
+
404
|
|
59
|
+
);
|
|
38
60
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
const html = fs.readFileSync(indexPath, "utf-8");
|
|
62
|
+
const configScript = `
|
|
63
|
+
<script src="/config.js"></script>
|
|
64
|
+
`;
|
|
65
|
+
const injected = html.replace(
|
|
66
|
+
"</head>",
|
|
67
|
+
`${configScript}</head>`
|
|
42
68
|
);
|
|
69
|
+
return c.html(injected);
|
|
43
70
|
});
|
|
44
71
|
serve({
|
|
45
72
|
fetch: app.fetch,
|
package/dist/hub/serve.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
interface HubAuthConfig {
|
|
2
|
+
mode: "keycloak";
|
|
3
|
+
serverUrl: string;
|
|
4
|
+
realm: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
audience?: string;
|
|
7
|
+
}
|
|
1
8
|
interface HubConfig {
|
|
2
9
|
port?: number;
|
|
3
10
|
registryUrl?: string;
|
|
11
|
+
auth?: HubAuthConfig;
|
|
4
12
|
}
|
|
5
13
|
declare function startHubServer(userConfig?: Partial<HubConfig>): Promise<void>;
|
|
6
14
|
|
|
7
|
-
export { type HubConfig, startHubServer };
|
|
15
|
+
export { type HubAuthConfig, type HubConfig, startHubServer };
|
package/dist/hub/serve.js
CHANGED
|
@@ -17,15 +17,34 @@ var DEFAULT_REGISTRY_URL = "http://localhost:3750";
|
|
|
17
17
|
async function startHubServer(userConfig) {
|
|
18
18
|
const config = {
|
|
19
19
|
port: userConfig?.port ?? DEFAULT_PORT,
|
|
20
|
-
registryUrl: userConfig?.registryUrl ?? DEFAULT_REGISTRY_URL
|
|
20
|
+
registryUrl: userConfig?.registryUrl ?? DEFAULT_REGISTRY_URL,
|
|
21
|
+
auth: userConfig?.auth
|
|
21
22
|
};
|
|
22
23
|
const app = new Hono();
|
|
24
|
+
app.get("/config.js", (c) => {
|
|
25
|
+
const clientConfig = {
|
|
26
|
+
registryUrl: config.registryUrl,
|
|
27
|
+
auth: config.auth ? {
|
|
28
|
+
mode: config.auth.mode,
|
|
29
|
+
serverUrl: config.auth.serverUrl,
|
|
30
|
+
realm: config.auth.realm,
|
|
31
|
+
clientId: config.auth.clientId,
|
|
32
|
+
audience: config.auth.audience
|
|
33
|
+
} : void 0
|
|
34
|
+
};
|
|
35
|
+
c.header("Content-Type", "application/javascript");
|
|
36
|
+
return c.body(
|
|
37
|
+
`window.__GRAPITY_CONFIG__ = ${JSON.stringify(clientConfig)};`
|
|
38
|
+
);
|
|
39
|
+
});
|
|
23
40
|
app.use("/v1/*", async (c) => {
|
|
24
41
|
const url = new URL(c.req.url);
|
|
25
42
|
const targetUrl = config.registryUrl + url.pathname + url.search;
|
|
43
|
+
const headers = new Headers(c.req.raw.headers);
|
|
44
|
+
headers.delete("host");
|
|
26
45
|
const response = await fetch(targetUrl, {
|
|
27
46
|
method: c.req.method,
|
|
28
|
-
headers
|
|
47
|
+
headers,
|
|
29
48
|
body: c.req.raw.body
|
|
30
49
|
});
|
|
31
50
|
return response;
|
|
@@ -33,13 +52,21 @@ async function startHubServer(userConfig) {
|
|
|
33
52
|
app.use("/*", serveStatic({ root: HUB_DIST_PATH }));
|
|
34
53
|
app.get("/*", async (c) => {
|
|
35
54
|
const indexPath = path.join(HUB_DIST_PATH, "index.html");
|
|
36
|
-
if (fs.existsSync(indexPath)) {
|
|
37
|
-
return c.
|
|
55
|
+
if (!fs.existsSync(indexPath)) {
|
|
56
|
+
return c.text(
|
|
57
|
+
"index.html not found. Build the project with 'bun run build' first.",
|
|
58
|
+
404
|
|
59
|
+
);
|
|
38
60
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
const html = fs.readFileSync(indexPath, "utf-8");
|
|
62
|
+
const configScript = `
|
|
63
|
+
<script src="/config.js"></script>
|
|
64
|
+
`;
|
|
65
|
+
const injected = html.replace(
|
|
66
|
+
"</head>",
|
|
67
|
+
`${configScript}</head>`
|
|
42
68
|
);
|
|
69
|
+
return c.html(injected);
|
|
43
70
|
});
|
|
44
71
|
serve({
|
|
45
72
|
fetch: app.fetch,
|
package/dist/index.html
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
12
|
-
<script
|
|
13
|
-
<
|
|
12
|
+
<script src="/config.js"></script>
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-JAhtTTW2.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-LDlidn22.css">
|
|
14
15
|
</head>
|
|
15
16
|
<body>
|
|
16
17
|
<div id="root"></div>
|
|
@@ -191,28 +191,35 @@ interface GatewayConfigStore {
|
|
|
191
191
|
deleteGatewayLogsOlderThan(days: number): Promise<void>;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
type RoleSource = "scope" | "realm_access.roles";
|
|
195
|
+
interface KeycloakAuthConfig {
|
|
196
|
+
mode: "keycloak";
|
|
197
|
+
serverUrl: string;
|
|
198
|
+
realm: string;
|
|
199
|
+
audience?: string;
|
|
200
|
+
roleSource?: RoleSource;
|
|
201
|
+
}
|
|
202
|
+
type AuthConfig = {
|
|
203
|
+
mode: "none";
|
|
204
|
+
} | KeycloakAuthConfig;
|
|
205
|
+
|
|
206
|
+
type DatabaseBackend = "sqlite" | "postgresql";
|
|
194
207
|
interface ServerConfig {
|
|
195
208
|
port: number;
|
|
196
|
-
database:
|
|
209
|
+
database: DatabaseBackend;
|
|
197
210
|
sqlitePath?: string;
|
|
198
211
|
postgresUrl?: string;
|
|
199
|
-
|
|
200
|
-
auth?: {
|
|
201
|
-
mode: "none" | "api-key" | "jwt";
|
|
202
|
-
apiKeyHashes?: string[];
|
|
203
|
-
jwtSecret?: string;
|
|
204
|
-
};
|
|
205
|
-
audit?: {
|
|
206
|
-
enabled: boolean;
|
|
207
|
-
};
|
|
212
|
+
auth: AuthConfig;
|
|
208
213
|
}
|
|
209
214
|
|
|
210
215
|
type AppEnv = {
|
|
211
216
|
Variables: {
|
|
212
217
|
store: SpecStore & GatewayConfigStore;
|
|
213
218
|
config: ServerConfig;
|
|
219
|
+
actor?: string;
|
|
220
|
+
claims?: Record<string, unknown>;
|
|
214
221
|
};
|
|
215
222
|
};
|
|
216
223
|
declare function createApp(config: ServerConfig, store: SpecStore & GatewayConfigStore): Hono<AppEnv, hono_types.BlankSchema, "/">;
|
|
217
224
|
|
|
218
|
-
export { type
|
|
225
|
+
export { type AuditAction as A, type CompatReport as C, type GatewayConfigStore as G, type Provision as P, type SpecStore as S, type Spec as a, type SpecVersion as b, type SpecFilters as c, type GatewayConfig as d, type GatewayConfigVersion as e, type GatewayLog as f, type GatewayLogFilters as g, type GatewayLogStats as h, createApp as i, type ServerConfig as j };
|
package/dist/registry/index.d.ts
CHANGED
package/dist/registry/index.js
CHANGED
|
@@ -1751,6 +1751,7 @@ var pushRoute = new Hono().post("/", async (c) => {
|
|
|
1751
1751
|
}
|
|
1752
1752
|
const store = c.get("store");
|
|
1753
1753
|
const service = new RegistryService(store);
|
|
1754
|
+
const actor = c.get("actor") ?? body.pushedBy;
|
|
1754
1755
|
try {
|
|
1755
1756
|
const result = await service.pushSpec(body.content, body.name, {
|
|
1756
1757
|
type: body.type,
|
|
@@ -1759,7 +1760,7 @@ var pushRoute = new Hono().post("/", async (c) => {
|
|
|
1759
1760
|
sourceRepo: body.sourceRepo,
|
|
1760
1761
|
tags: Array.isArray(body.tags) ? body.tags : void 0,
|
|
1761
1762
|
gitRef: body.gitRef,
|
|
1762
|
-
pushedBy:
|
|
1763
|
+
pushedBy: actor,
|
|
1763
1764
|
prerelease: body.prerelease,
|
|
1764
1765
|
force: body.force,
|
|
1765
1766
|
reason: body.reason
|
|
@@ -1924,7 +1925,8 @@ var deleteSpecRoute = new Hono5().delete(
|
|
|
1924
1925
|
const name = c.req.param("name");
|
|
1925
1926
|
const store = c.get("store");
|
|
1926
1927
|
const service = new RegistryService(store);
|
|
1927
|
-
const
|
|
1928
|
+
const actor = c.get("actor");
|
|
1929
|
+
const deleted = await service.deleteSpec(name, actor);
|
|
1928
1930
|
if (!deleted) {
|
|
1929
1931
|
return c.json({ error: "not_found", message: `Spec "${name}" not found`, statusCode: 404 }, 404);
|
|
1930
1932
|
}
|
|
@@ -2525,8 +2527,7 @@ function switchTab(tab) {
|
|
|
2525
2527
|
}
|
|
2526
2528
|
var welcomeRoute = new Hono12().get("/", (c) => {
|
|
2527
2529
|
const config = c.get("config");
|
|
2528
|
-
|
|
2529
|
-
return c.html(buildPage(config.port, mode));
|
|
2530
|
+
return c.html(buildPage(config.port, "local"));
|
|
2530
2531
|
});
|
|
2531
2532
|
|
|
2532
2533
|
// src/registry/routes/push-gateway-config.ts
|
|
@@ -2666,6 +2667,7 @@ var pushGatewayConfigRoute = new Hono13().post("/", async (c) => {
|
|
|
2666
2667
|
}
|
|
2667
2668
|
const store = c.get("store");
|
|
2668
2669
|
const service = new GatewayService(store, store);
|
|
2670
|
+
const actor = c.get("actor") ?? body.pushedBy;
|
|
2669
2671
|
try {
|
|
2670
2672
|
const result = await service.pushGatewayConfig({
|
|
2671
2673
|
name: body.name,
|
|
@@ -2676,7 +2678,7 @@ var pushGatewayConfigRoute = new Hono13().post("/", async (c) => {
|
|
|
2676
2678
|
environments: body.environments ?? {},
|
|
2677
2679
|
callerIdentification: body.callerIdentification,
|
|
2678
2680
|
content: body.content,
|
|
2679
|
-
pushedBy:
|
|
2681
|
+
pushedBy: actor
|
|
2680
2682
|
});
|
|
2681
2683
|
return c.json({ data: result }, 201);
|
|
2682
2684
|
} catch (err) {
|
|
@@ -2867,7 +2869,6 @@ var ingestGatewayLogRoute = new Hono18().post("/ingest/:provider/:environment",
|
|
|
2867
2869
|
await service.ingestLog(provider, environment, payload);
|
|
2868
2870
|
return c.json({ status: "ok" }, 201);
|
|
2869
2871
|
} catch (err) {
|
|
2870
|
-
console.error("Gateway log ingest error:", err);
|
|
2871
2872
|
return c.json({
|
|
2872
2873
|
error: "bad_request",
|
|
2873
2874
|
message: err instanceof Error ? err.message : "Invalid log payload",
|
|
@@ -2942,7 +2943,137 @@ var gatewayLogStatsRoute = new Hono21().get("/stats", async (c) => {
|
|
|
2942
2943
|
});
|
|
2943
2944
|
});
|
|
2944
2945
|
|
|
2946
|
+
// src/registry/auth/middleware.ts
|
|
2947
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
2948
|
+
var AuthError = class extends Error {
|
|
2949
|
+
constructor(statusCode, code, message) {
|
|
2950
|
+
super(message);
|
|
2951
|
+
this.statusCode = statusCode;
|
|
2952
|
+
this.code = code;
|
|
2953
|
+
this.name = "AuthError";
|
|
2954
|
+
}
|
|
2955
|
+
statusCode;
|
|
2956
|
+
code;
|
|
2957
|
+
};
|
|
2958
|
+
function buildKeycloakUrls(config) {
|
|
2959
|
+
const base = `${config.serverUrl}/realms/${config.realm}`;
|
|
2960
|
+
return {
|
|
2961
|
+
issuer: base,
|
|
2962
|
+
jwksUri: `${base}/protocol/openid-connect/certs`,
|
|
2963
|
+
tokenUrl: `${base}/protocol/openid-connect/token`
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
function createAuthMiddleware(config, routeScopes) {
|
|
2967
|
+
if (config.auth?.mode !== "keycloak") {
|
|
2968
|
+
return async (_c, next) => await next();
|
|
2969
|
+
}
|
|
2970
|
+
const authConfig = config.auth;
|
|
2971
|
+
const { issuer, jwksUri } = buildKeycloakUrls(authConfig);
|
|
2972
|
+
const jwks = createRemoteJWKSet(new URL(jwksUri));
|
|
2973
|
+
const scopeByRoute = /* @__PURE__ */ new Map();
|
|
2974
|
+
for (const route of routeScopes) {
|
|
2975
|
+
const key = `${route.method.toUpperCase()}:${route.path}`;
|
|
2976
|
+
scopeByRoute.set(key, {
|
|
2977
|
+
operationId: route.operationId,
|
|
2978
|
+
scopes: route.scopes
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
return async (c, next) => {
|
|
2982
|
+
const matchedPath = c.req.matchedRoutes.map((r) => r.path).filter((p) => p !== "/*").pop();
|
|
2983
|
+
const routeKey = matchedPath ? `${c.req.method}:${matchedPath}` : `${c.req.method}:${c.req.routePath}`;
|
|
2984
|
+
const required = scopeByRoute.get(routeKey);
|
|
2985
|
+
if (!required || required.scopes.length === 0) {
|
|
2986
|
+
return await next();
|
|
2987
|
+
}
|
|
2988
|
+
const authHeader = c.req.header("Authorization");
|
|
2989
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
2990
|
+
throw new AuthError(401, "unauthorized", "Bearer token required");
|
|
2991
|
+
}
|
|
2992
|
+
const token = authHeader.slice("Bearer ".length).trim();
|
|
2993
|
+
if (!token) {
|
|
2994
|
+
throw new AuthError(401, "unauthorized", "Bearer token required");
|
|
2995
|
+
}
|
|
2996
|
+
let payload;
|
|
2997
|
+
try {
|
|
2998
|
+
const result = await jwtVerify(token, jwks, {
|
|
2999
|
+
issuer,
|
|
3000
|
+
audience: authConfig.audience
|
|
3001
|
+
});
|
|
3002
|
+
payload = result.payload;
|
|
3003
|
+
} catch (err) {
|
|
3004
|
+
const message = err instanceof Error ? err.message : "Invalid token";
|
|
3005
|
+
throw new AuthError(401, "unauthorized", `Invalid or expired token: ${message}`);
|
|
3006
|
+
}
|
|
3007
|
+
const subject = payload.sub;
|
|
3008
|
+
if (!subject) {
|
|
3009
|
+
throw new AuthError(401, "unauthorized", "Token missing subject claim");
|
|
3010
|
+
}
|
|
3011
|
+
const grantedScopes = extractScopes(payload, authConfig.roleSource ?? "scope");
|
|
3012
|
+
const missing = required.scopes.filter((s) => !grantedScopes.has(s));
|
|
3013
|
+
if (missing.length > 0) {
|
|
3014
|
+
throw new AuthError(
|
|
3015
|
+
403,
|
|
3016
|
+
"forbidden",
|
|
3017
|
+
`Missing required scope${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
|
|
3018
|
+
);
|
|
3019
|
+
}
|
|
3020
|
+
c.set("actor", subject);
|
|
3021
|
+
c.set("claims", payload);
|
|
3022
|
+
await next();
|
|
3023
|
+
};
|
|
3024
|
+
}
|
|
3025
|
+
function extractScopes(payload, source) {
|
|
3026
|
+
if (source === "realm_access.roles") {
|
|
3027
|
+
const roles = payload.realm_access?.roles;
|
|
3028
|
+
return new Set(roles ?? []);
|
|
3029
|
+
}
|
|
3030
|
+
const scopeValue = payload.scope;
|
|
3031
|
+
if (typeof scopeValue === "string") {
|
|
3032
|
+
return new Set(scopeValue.split(/\s+/).filter(Boolean));
|
|
3033
|
+
}
|
|
3034
|
+
return /* @__PURE__ */ new Set();
|
|
3035
|
+
}
|
|
3036
|
+
function parseRouteScopes(spec) {
|
|
3037
|
+
const routes = [];
|
|
3038
|
+
const paths = spec.paths;
|
|
3039
|
+
if (!paths) return routes;
|
|
3040
|
+
for (const [path, operations] of Object.entries(paths)) {
|
|
3041
|
+
for (const [method, operation] of Object.entries(operations)) {
|
|
3042
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
3043
|
+
const op = operation;
|
|
3044
|
+
const operationId = op.operationId;
|
|
3045
|
+
if (!operationId) continue;
|
|
3046
|
+
const security = op.security;
|
|
3047
|
+
const scopes = [];
|
|
3048
|
+
if (security) {
|
|
3049
|
+
for (const sec of security) {
|
|
3050
|
+
for (const [name, required] of Object.entries(sec)) {
|
|
3051
|
+
if (name === "keycloak" && Array.isArray(required)) {
|
|
3052
|
+
scopes.push(...required);
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
routes.push({
|
|
3058
|
+
method: method.toUpperCase(),
|
|
3059
|
+
path: path.replace(/\{([^}]+)\}/g, ":$1"),
|
|
3060
|
+
operationId,
|
|
3061
|
+
scopes
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
return routes;
|
|
3066
|
+
}
|
|
3067
|
+
|
|
2945
3068
|
// src/registry/server.ts
|
|
3069
|
+
import { readFileSync } from "fs";
|
|
3070
|
+
import { fileURLToPath } from "url";
|
|
3071
|
+
import yaml6 from "js-yaml";
|
|
3072
|
+
function loadOpenApiSpec() {
|
|
3073
|
+
const path = fileURLToPath(new URL("../../openapi.yaml", import.meta.url));
|
|
3074
|
+
const content = readFileSync(path, "utf-8");
|
|
3075
|
+
return yaml6.load(content);
|
|
3076
|
+
}
|
|
2946
3077
|
function createApp(config, store) {
|
|
2947
3078
|
const app = new Hono22();
|
|
2948
3079
|
app.use("*", logger());
|
|
@@ -2953,6 +3084,21 @@ function createApp(config, store) {
|
|
|
2953
3084
|
c.set("config", config);
|
|
2954
3085
|
await next();
|
|
2955
3086
|
});
|
|
3087
|
+
const routeScopes = parseRouteScopes(loadOpenApiSpec());
|
|
3088
|
+
app.use("*", createAuthMiddleware(config, routeScopes));
|
|
3089
|
+
app.onError((err, c) => {
|
|
3090
|
+
if (err instanceof AuthError) {
|
|
3091
|
+
return c.json(
|
|
3092
|
+
{ error: err.code, message: err.message, statusCode: err.statusCode },
|
|
3093
|
+
err.statusCode
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
3096
|
+
console.error("Unhandled error:", err);
|
|
3097
|
+
return c.json(
|
|
3098
|
+
{ error: "internal_error", message: "Internal server error", statusCode: 500 },
|
|
3099
|
+
500
|
|
3100
|
+
);
|
|
3101
|
+
});
|
|
2956
3102
|
app.route("/v1/specs", pushRoute);
|
|
2957
3103
|
app.route("/v1/specs", validateRoute);
|
|
2958
3104
|
app.route("/v1/specs", listRoute);
|
package/dist/registry/serve.d.ts
CHANGED
|
@@ -1,7 +1,98 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { ServerType } from '@hono/node-server';
|
|
2
|
+
import { S as SpecStore, G as GatewayConfigStore, a as Spec, b as SpecVersion, c as SpecFilters, C as CompatReport, A as AuditAction, d as GatewayConfig, e as GatewayConfigVersion, P as Provision, f as GatewayLog, g as GatewayLogFilters, h as GatewayLogStats, i as createApp, j as ServerConfig } from './index-Bx-7YlUF.js';
|
|
3
|
+
import 'hono/types';
|
|
4
|
+
import 'hono';
|
|
4
5
|
|
|
5
|
-
declare
|
|
6
|
+
declare class SQLiteSpecStore implements SpecStore, GatewayConfigStore {
|
|
7
|
+
private db;
|
|
8
|
+
constructor(dbPath: string);
|
|
9
|
+
migrate(): Promise<void>;
|
|
10
|
+
getSpec(name: string): Promise<Spec | null>;
|
|
11
|
+
getSpecVersion(name: string, semver: string): Promise<SpecVersion | null>;
|
|
12
|
+
getLatestVersion(name: string): Promise<SpecVersion | null>;
|
|
13
|
+
listSpecs(filters?: SpecFilters): Promise<Spec[]>;
|
|
14
|
+
listVersions(name: string, options?: {
|
|
15
|
+
limit?: number;
|
|
16
|
+
offset?: number;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
versions: SpecVersion[];
|
|
19
|
+
total: number;
|
|
20
|
+
}>;
|
|
21
|
+
pushSpecVersion(spec: Spec, version: SpecVersion): Promise<SpecVersion>;
|
|
22
|
+
deleteSpec(name: string): Promise<boolean>;
|
|
23
|
+
getCompatReport(name: string, semver: string): Promise<CompatReport | null>;
|
|
24
|
+
logAudit(action: AuditAction, actor: string, specName: string, version: string | undefined, details: Record<string, unknown> | undefined): Promise<void>;
|
|
25
|
+
private mapSpecRow;
|
|
26
|
+
private mapVersionRow;
|
|
27
|
+
getGatewayConfig(name: string): Promise<GatewayConfig | null>;
|
|
28
|
+
listGatewayConfigs(): Promise<GatewayConfig[]>;
|
|
29
|
+
getGatewayConfigVersion(name: string, versionId: string): Promise<GatewayConfigVersion | null>;
|
|
30
|
+
getLatestGatewayConfigVersion(name: string): Promise<GatewayConfigVersion | null>;
|
|
31
|
+
listGatewayConfigVersions(name: string): Promise<GatewayConfigVersion[]>;
|
|
32
|
+
pushGatewayConfigVersion(config: GatewayConfig, version: GatewayConfigVersion): Promise<GatewayConfigVersion>;
|
|
33
|
+
recordProvision(provision: Provision): Promise<void>;
|
|
34
|
+
listProvisions(gatewayConfigName?: string): Promise<Provision[]>;
|
|
35
|
+
private mapGatewayConfigRow;
|
|
36
|
+
private mapGatewayConfigVersionRow;
|
|
37
|
+
recordGatewayLog(log: GatewayLog): Promise<void>;
|
|
38
|
+
listGatewayLogs(filters: GatewayLogFilters): Promise<{
|
|
39
|
+
logs: GatewayLog[];
|
|
40
|
+
total: number;
|
|
41
|
+
}>;
|
|
42
|
+
getGatewayLog(id: string): Promise<GatewayLog | null>;
|
|
43
|
+
getGatewayLogStats(_filters: GatewayLogFilters): Promise<GatewayLogStats[]>;
|
|
44
|
+
deleteGatewayLogsOlderThan(days: number): Promise<void>;
|
|
45
|
+
}
|
|
6
46
|
|
|
7
|
-
|
|
47
|
+
declare class PostgreSQLSpecStore implements SpecStore, GatewayConfigStore {
|
|
48
|
+
private db;
|
|
49
|
+
private pool;
|
|
50
|
+
private postgresUrl;
|
|
51
|
+
constructor(postgresUrl: string);
|
|
52
|
+
migrate(): Promise<void>;
|
|
53
|
+
end(): Promise<void>;
|
|
54
|
+
getSpec(name: string): Promise<Spec | null>;
|
|
55
|
+
getSpecVersion(name: string, semver: string): Promise<SpecVersion | null>;
|
|
56
|
+
getLatestVersion(name: string): Promise<SpecVersion | null>;
|
|
57
|
+
listSpecs(filters?: SpecFilters): Promise<Spec[]>;
|
|
58
|
+
listVersions(name: string, options?: {
|
|
59
|
+
limit?: number;
|
|
60
|
+
offset?: number;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
versions: SpecVersion[];
|
|
63
|
+
total: number;
|
|
64
|
+
}>;
|
|
65
|
+
pushSpecVersion(spec: Spec, version: SpecVersion): Promise<SpecVersion>;
|
|
66
|
+
deleteSpec(name: string): Promise<boolean>;
|
|
67
|
+
getCompatReport(name: string, semver: string): Promise<CompatReport | null>;
|
|
68
|
+
logAudit(action: AuditAction, actor: string, specName: string, version: string | undefined, details: Record<string, unknown> | undefined): Promise<void>;
|
|
69
|
+
private mapSpecRow;
|
|
70
|
+
private mapVersionRow;
|
|
71
|
+
getGatewayConfig(name: string): Promise<GatewayConfig | null>;
|
|
72
|
+
listGatewayConfigs(): Promise<GatewayConfig[]>;
|
|
73
|
+
getGatewayConfigVersion(name: string, versionId: string): Promise<GatewayConfigVersion | null>;
|
|
74
|
+
getLatestGatewayConfigVersion(name: string): Promise<GatewayConfigVersion | null>;
|
|
75
|
+
listGatewayConfigVersions(name: string): Promise<GatewayConfigVersion[]>;
|
|
76
|
+
pushGatewayConfigVersion(config: GatewayConfig, version: GatewayConfigVersion): Promise<GatewayConfigVersion>;
|
|
77
|
+
recordProvision(provision: Provision): Promise<void>;
|
|
78
|
+
listProvisions(gatewayConfigName?: string): Promise<Provision[]>;
|
|
79
|
+
private mapGatewayConfigRow;
|
|
80
|
+
private mapGatewayConfigVersionRow;
|
|
81
|
+
recordGatewayLog(log: GatewayLog): Promise<void>;
|
|
82
|
+
listGatewayLogs(filters: GatewayLogFilters): Promise<{
|
|
83
|
+
logs: GatewayLog[];
|
|
84
|
+
total: number;
|
|
85
|
+
}>;
|
|
86
|
+
getGatewayLog(id: string): Promise<GatewayLog | null>;
|
|
87
|
+
getGatewayLogStats(_filters: GatewayLogFilters): Promise<GatewayLogStats[]>;
|
|
88
|
+
deleteGatewayLogsOlderThan(days: number): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface RunningServer {
|
|
92
|
+
app: ReturnType<typeof createApp>;
|
|
93
|
+
store: SQLiteSpecStore | PostgreSQLSpecStore;
|
|
94
|
+
server: ServerType;
|
|
95
|
+
}
|
|
96
|
+
declare function startServer(userConfig?: Partial<ServerConfig>): Promise<RunningServer>;
|
|
97
|
+
|
|
98
|
+
export { type RunningServer, ServerConfig, startServer };
|