@grapity/grapity 0.3.0 → 0.4.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 +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 +794 -69
- 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-DUPbMrAe.d.ts → index-Bx-7YlUF.d.ts} +15 -0
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +298 -3
- package/dist/registry/serve.d.ts +2 -1
- package/dist/registry/serve.js +349 -7
- package/package.json +13 -11
- 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,18 +191,33 @@ 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
|
+
|
|
194
206
|
type DatabaseBackend = "sqlite" | "postgresql";
|
|
195
207
|
interface ServerConfig {
|
|
196
208
|
port: number;
|
|
197
209
|
database: DatabaseBackend;
|
|
198
210
|
sqlitePath?: string;
|
|
199
211
|
postgresUrl?: string;
|
|
212
|
+
auth: AuthConfig;
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
type AppEnv = {
|
|
203
216
|
Variables: {
|
|
204
217
|
store: SpecStore & GatewayConfigStore;
|
|
205
218
|
config: ServerConfig;
|
|
219
|
+
actor?: string;
|
|
220
|
+
claims?: Record<string, unknown>;
|
|
206
221
|
};
|
|
207
222
|
};
|
|
208
223
|
declare function createApp(config: ServerConfig, store: SpecStore & GatewayConfigStore): Hono<AppEnv, hono_types.BlankSchema, "/">;
|
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
|
}
|
|
@@ -2665,6 +2667,7 @@ var pushGatewayConfigRoute = new Hono13().post("/", async (c) => {
|
|
|
2665
2667
|
}
|
|
2666
2668
|
const store = c.get("store");
|
|
2667
2669
|
const service = new GatewayService(store, store);
|
|
2670
|
+
const actor = c.get("actor") ?? body.pushedBy;
|
|
2668
2671
|
try {
|
|
2669
2672
|
const result = await service.pushGatewayConfig({
|
|
2670
2673
|
name: body.name,
|
|
@@ -2675,7 +2678,7 @@ var pushGatewayConfigRoute = new Hono13().post("/", async (c) => {
|
|
|
2675
2678
|
environments: body.environments ?? {},
|
|
2676
2679
|
callerIdentification: body.callerIdentification,
|
|
2677
2680
|
content: body.content,
|
|
2678
|
-
pushedBy:
|
|
2681
|
+
pushedBy: actor
|
|
2679
2682
|
});
|
|
2680
2683
|
return c.json({ data: result }, 201);
|
|
2681
2684
|
} catch (err) {
|
|
@@ -2940,6 +2943,283 @@ var gatewayLogStatsRoute = new Hono21().get("/stats", async (c) => {
|
|
|
2940
2943
|
});
|
|
2941
2944
|
});
|
|
2942
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, routeScopes2) {
|
|
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 routeScopes2) {
|
|
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
|
+
|
|
3037
|
+
// src/registry/generated/route-scopes.ts
|
|
3038
|
+
var routeScopes = [
|
|
3039
|
+
{
|
|
3040
|
+
"method": "GET",
|
|
3041
|
+
"path": "/v1/health",
|
|
3042
|
+
"operationId": "getHealth",
|
|
3043
|
+
"scopes": []
|
|
3044
|
+
},
|
|
3045
|
+
{
|
|
3046
|
+
"method": "GET",
|
|
3047
|
+
"path": "/v1/specs",
|
|
3048
|
+
"operationId": "listSpecs",
|
|
3049
|
+
"scopes": [
|
|
3050
|
+
"specs:read"
|
|
3051
|
+
]
|
|
3052
|
+
},
|
|
3053
|
+
{
|
|
3054
|
+
"method": "POST",
|
|
3055
|
+
"path": "/v1/specs",
|
|
3056
|
+
"operationId": "pushSpec",
|
|
3057
|
+
"scopes": [
|
|
3058
|
+
"specs:write"
|
|
3059
|
+
]
|
|
3060
|
+
},
|
|
3061
|
+
{
|
|
3062
|
+
"method": "GET",
|
|
3063
|
+
"path": "/v1/specs/:name",
|
|
3064
|
+
"operationId": "getSpec",
|
|
3065
|
+
"scopes": [
|
|
3066
|
+
"specs:read"
|
|
3067
|
+
]
|
|
3068
|
+
},
|
|
3069
|
+
{
|
|
3070
|
+
"method": "DELETE",
|
|
3071
|
+
"path": "/v1/specs/:name",
|
|
3072
|
+
"operationId": "deleteSpec",
|
|
3073
|
+
"scopes": [
|
|
3074
|
+
"specs:write"
|
|
3075
|
+
]
|
|
3076
|
+
},
|
|
3077
|
+
{
|
|
3078
|
+
"method": "POST",
|
|
3079
|
+
"path": "/v1/specs/:name/validate",
|
|
3080
|
+
"operationId": "validateSpec",
|
|
3081
|
+
"scopes": [
|
|
3082
|
+
"specs:write"
|
|
3083
|
+
]
|
|
3084
|
+
},
|
|
3085
|
+
{
|
|
3086
|
+
"method": "GET",
|
|
3087
|
+
"path": "/v1/specs/:name/versions",
|
|
3088
|
+
"operationId": "listVersions",
|
|
3089
|
+
"scopes": [
|
|
3090
|
+
"specs:read"
|
|
3091
|
+
]
|
|
3092
|
+
},
|
|
3093
|
+
{
|
|
3094
|
+
"method": "GET",
|
|
3095
|
+
"path": "/v1/specs/:name/versions/:semver",
|
|
3096
|
+
"operationId": "getVersion",
|
|
3097
|
+
"scopes": [
|
|
3098
|
+
"specs:read"
|
|
3099
|
+
]
|
|
3100
|
+
},
|
|
3101
|
+
{
|
|
3102
|
+
"method": "GET",
|
|
3103
|
+
"path": "/v1/specs/:name/spec.json",
|
|
3104
|
+
"operationId": "getSpecJson",
|
|
3105
|
+
"scopes": [
|
|
3106
|
+
"specs:read"
|
|
3107
|
+
]
|
|
3108
|
+
},
|
|
3109
|
+
{
|
|
3110
|
+
"method": "GET",
|
|
3111
|
+
"path": "/v1/specs/:name/spec.yaml",
|
|
3112
|
+
"operationId": "getSpecYaml",
|
|
3113
|
+
"scopes": [
|
|
3114
|
+
"specs:read"
|
|
3115
|
+
]
|
|
3116
|
+
},
|
|
3117
|
+
{
|
|
3118
|
+
"method": "GET",
|
|
3119
|
+
"path": "/v1/specs/:name/versions/:semver/spec.json",
|
|
3120
|
+
"operationId": "getVersionSpecJson",
|
|
3121
|
+
"scopes": [
|
|
3122
|
+
"specs:read"
|
|
3123
|
+
]
|
|
3124
|
+
},
|
|
3125
|
+
{
|
|
3126
|
+
"method": "GET",
|
|
3127
|
+
"path": "/v1/specs/:name/versions/:semver/spec.yaml",
|
|
3128
|
+
"operationId": "getVersionSpecYaml",
|
|
3129
|
+
"scopes": [
|
|
3130
|
+
"specs:read"
|
|
3131
|
+
]
|
|
3132
|
+
},
|
|
3133
|
+
{
|
|
3134
|
+
"method": "GET",
|
|
3135
|
+
"path": "/v1/specs/:name/compat/:semver",
|
|
3136
|
+
"operationId": "getCompatReport",
|
|
3137
|
+
"scopes": [
|
|
3138
|
+
"specs:read"
|
|
3139
|
+
]
|
|
3140
|
+
},
|
|
3141
|
+
{
|
|
3142
|
+
"method": "GET",
|
|
3143
|
+
"path": "/v1/specs/:name/compare",
|
|
3144
|
+
"operationId": "compareVersions",
|
|
3145
|
+
"scopes": [
|
|
3146
|
+
"specs:read"
|
|
3147
|
+
]
|
|
3148
|
+
},
|
|
3149
|
+
{
|
|
3150
|
+
"method": "GET",
|
|
3151
|
+
"path": "/v1/gateway-configs",
|
|
3152
|
+
"operationId": "listGatewayConfigs",
|
|
3153
|
+
"scopes": [
|
|
3154
|
+
"gateway-configs:read"
|
|
3155
|
+
]
|
|
3156
|
+
},
|
|
3157
|
+
{
|
|
3158
|
+
"method": "POST",
|
|
3159
|
+
"path": "/v1/gateway-configs",
|
|
3160
|
+
"operationId": "pushGatewayConfig",
|
|
3161
|
+
"scopes": [
|
|
3162
|
+
"gateway-configs:write"
|
|
3163
|
+
]
|
|
3164
|
+
},
|
|
3165
|
+
{
|
|
3166
|
+
"method": "GET",
|
|
3167
|
+
"path": "/v1/gateway-configs/:name",
|
|
3168
|
+
"operationId": "getGatewayConfig",
|
|
3169
|
+
"scopes": [
|
|
3170
|
+
"gateway-configs:read"
|
|
3171
|
+
]
|
|
3172
|
+
},
|
|
3173
|
+
{
|
|
3174
|
+
"method": "GET",
|
|
3175
|
+
"path": "/v1/gateway-configs/:name/versions",
|
|
3176
|
+
"operationId": "listGatewayConfigVersions",
|
|
3177
|
+
"scopes": [
|
|
3178
|
+
"gateway-configs:read"
|
|
3179
|
+
]
|
|
3180
|
+
},
|
|
3181
|
+
{
|
|
3182
|
+
"method": "GET",
|
|
3183
|
+
"path": "/v1/gateway-configs/:name/versions/:versionId",
|
|
3184
|
+
"operationId": "getGatewayConfigVersion",
|
|
3185
|
+
"scopes": [
|
|
3186
|
+
"gateway-configs:read"
|
|
3187
|
+
]
|
|
3188
|
+
},
|
|
3189
|
+
{
|
|
3190
|
+
"method": "POST",
|
|
3191
|
+
"path": "/v1/gateway-logs/ingest/:provider/:environment",
|
|
3192
|
+
"operationId": "ingestGatewayLog",
|
|
3193
|
+
"scopes": [
|
|
3194
|
+
"gateway-logs:write"
|
|
3195
|
+
]
|
|
3196
|
+
},
|
|
3197
|
+
{
|
|
3198
|
+
"method": "GET",
|
|
3199
|
+
"path": "/v1/gateway-logs",
|
|
3200
|
+
"operationId": "listGatewayLogs",
|
|
3201
|
+
"scopes": [
|
|
3202
|
+
"gateway-logs:read"
|
|
3203
|
+
]
|
|
3204
|
+
},
|
|
3205
|
+
{
|
|
3206
|
+
"method": "GET",
|
|
3207
|
+
"path": "/v1/gateway-logs/stats",
|
|
3208
|
+
"operationId": "getGatewayLogStats",
|
|
3209
|
+
"scopes": [
|
|
3210
|
+
"gateway-logs:read"
|
|
3211
|
+
]
|
|
3212
|
+
},
|
|
3213
|
+
{
|
|
3214
|
+
"method": "GET",
|
|
3215
|
+
"path": "/v1/gateway-logs/:id",
|
|
3216
|
+
"operationId": "getGatewayLog",
|
|
3217
|
+
"scopes": [
|
|
3218
|
+
"gateway-logs:read"
|
|
3219
|
+
]
|
|
3220
|
+
}
|
|
3221
|
+
];
|
|
3222
|
+
|
|
2943
3223
|
// src/registry/server.ts
|
|
2944
3224
|
function createApp(config, store) {
|
|
2945
3225
|
const app = new Hono22();
|
|
@@ -2951,6 +3231,21 @@ function createApp(config, store) {
|
|
|
2951
3231
|
c.set("config", config);
|
|
2952
3232
|
await next();
|
|
2953
3233
|
});
|
|
3234
|
+
const authRouteScopes = config.auth?.mode === "keycloak" ? routeScopes : [];
|
|
3235
|
+
app.use("*", createAuthMiddleware(config, authRouteScopes));
|
|
3236
|
+
app.onError((err, c) => {
|
|
3237
|
+
if (err instanceof AuthError) {
|
|
3238
|
+
return c.json(
|
|
3239
|
+
{ error: err.code, message: err.message, statusCode: err.statusCode },
|
|
3240
|
+
err.statusCode
|
|
3241
|
+
);
|
|
3242
|
+
}
|
|
3243
|
+
console.error("Unhandled error:", err);
|
|
3244
|
+
return c.json(
|
|
3245
|
+
{ error: "internal_error", message: "Internal server error", statusCode: 500 },
|
|
3246
|
+
500
|
|
3247
|
+
);
|
|
3248
|
+
});
|
|
2954
3249
|
app.route("/v1/specs", pushRoute);
|
|
2955
3250
|
app.route("/v1/specs", validateRoute);
|
|
2956
3251
|
app.route("/v1/specs", listRoute);
|
package/dist/registry/serve.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-
|
|
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
3
|
import 'hono/types';
|
|
4
4
|
import 'hono';
|
|
5
5
|
|
|
@@ -47,6 +47,7 @@ declare class SQLiteSpecStore implements SpecStore, GatewayConfigStore {
|
|
|
47
47
|
declare class PostgreSQLSpecStore implements SpecStore, GatewayConfigStore {
|
|
48
48
|
private db;
|
|
49
49
|
private pool;
|
|
50
|
+
private postgresUrl;
|
|
50
51
|
constructor(postgresUrl: string);
|
|
51
52
|
migrate(): Promise<void>;
|
|
52
53
|
end(): Promise<void>;
|