@open-rap/runtime 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +14 -2
- package/dist/abap/background.d.ts +14 -0
- package/dist/abap/background.js +130 -0
- package/dist/abap/background.js.map +1 -0
- package/dist/abap/bridge.d.ts +62 -0
- package/dist/abap/bridge.js +402 -0
- package/dist/abap/bridge.js.map +1 -0
- package/dist/abap/convert.d.ts +26 -0
- package/dist/abap/convert.js +197 -0
- package/dist/abap/convert.js.map +1 -0
- package/dist/abap/http.d.ts +34 -0
- package/dist/abap/http.js +133 -0
- package/dist/abap/http.js.map +1 -0
- package/dist/abap/mail.d.ts +10 -0
- package/dist/abap/mail.js +83 -0
- package/dist/abap/mail.js.map +1 -0
- package/dist/abap/odata-client.d.ts +33 -0
- package/dist/abap/odata-client.js +576 -0
- package/dist/abap/odata-client.js.map +1 -0
- package/dist/abap/sql.d.ts +92 -0
- package/dist/abap/sql.js +261 -0
- package/dist/abap/sql.js.map +1 -0
- package/dist/abap/utils.d.ts +41 -0
- package/dist/abap/utils.js +976 -0
- package/dist/abap/utils.js.map +1 -0
- package/dist/app.d.ts +53 -0
- package/dist/app.js +169 -0
- package/dist/app.js.map +1 -0
- package/dist/auth/auth.d.ts +68 -0
- package/dist/auth/auth.js +140 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/authorizations.d.ts +39 -0
- package/dist/auth/authorizations.js +103 -0
- package/dist/auth/authorizations.js.map +1 -0
- package/dist/auth/business-users.d.ts +15 -0
- package/dist/auth/business-users.js +36 -0
- package/dist/auth/business-users.js.map +1 -0
- package/dist/auth/dev-oauth.d.ts +38 -0
- package/dist/auth/dev-oauth.js +156 -0
- package/dist/auth/dev-oauth.js.map +1 -0
- package/dist/auth/environment.d.ts +7 -0
- package/dist/auth/environment.js +57 -0
- package/dist/auth/environment.js.map +1 -0
- package/dist/auth/session.d.ts +45 -0
- package/dist/auth/session.js +257 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/user.d.ts +21 -0
- package/dist/auth/user.js +12 -0
- package/dist/auth/user.js.map +1 -0
- package/dist/db/database.d.ts +30 -0
- package/dist/db/database.js +131 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/seed.d.ts +9 -0
- package/dist/db/seed.js +63 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/launchpad/dev.d.ts +14 -0
- package/dist/launchpad/dev.js +48 -0
- package/dist/launchpad/dev.js.map +1 -0
- package/dist/launchpad/proxy.d.ts +30 -0
- package/dist/launchpad/proxy.js +98 -0
- package/dist/launchpad/proxy.js.map +1 -0
- package/dist/launchpad/server.d.ts +77 -0
- package/dist/launchpad/server.js +177 -0
- package/dist/launchpad/server.js.map +1 -0
- package/dist/mcp/server.d.ts +22 -0
- package/dist/mcp/server.js +222 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/odata/access.d.ts +31 -0
- package/dist/odata/access.js +142 -0
- package/dist/odata/access.js.map +1 -0
- package/dist/odata/batch.d.ts +36 -0
- package/dist/odata/batch.js +147 -0
- package/dist/odata/batch.js.map +1 -0
- package/dist/odata/csrf.d.ts +13 -0
- package/dist/odata/csrf.js +27 -0
- package/dist/odata/csrf.js.map +1 -0
- package/dist/odata/custom.d.ts +90 -0
- package/dist/odata/custom.js +373 -0
- package/dist/odata/custom.js.map +1 -0
- package/dist/odata/draft.d.ts +78 -0
- package/dist/odata/draft.js +590 -0
- package/dist/odata/draft.js.map +1 -0
- package/dist/odata/errors.d.ts +27 -0
- package/dist/odata/errors.js +41 -0
- package/dist/odata/errors.js.map +1 -0
- package/dist/odata/handler.d.ts +90 -0
- package/dist/odata/handler.js +312 -0
- package/dist/odata/handler.js.map +1 -0
- package/dist/odata/json.d.ts +23 -0
- package/dist/odata/json.js +85 -0
- package/dist/odata/json.js.map +1 -0
- package/dist/odata/read.d.ts +90 -0
- package/dist/odata/read.js +686 -0
- package/dist/odata/read.js.map +1 -0
- package/dist/odata/service.d.ts +45 -0
- package/dist/odata/service.js +145 -0
- package/dist/odata/service.js.map +1 -0
- package/dist/odata/uri/ast.d.ts +103 -0
- package/dist/odata/uri/ast.js +3 -0
- package/dist/odata/uri/ast.js.map +1 -0
- package/dist/odata/uri/parser.d.ts +26 -0
- package/dist/odata/uri/parser.js +697 -0
- package/dist/odata/uri/parser.js.map +1 -0
- package/dist/odata/write.d.ts +127 -0
- package/dist/odata/write.js +799 -0
- package/dist/odata/write.js.map +1 -0
- package/dist/platform.d.ts +14 -0
- package/dist/platform.js +66 -0
- package/dist/platform.js.map +1 -0
- package/dist/rap/bo.d.ts +76 -0
- package/dist/rap/bo.js +184 -0
- package/dist/rap/bo.js.map +1 -0
- package/dist/rap/kernel.d.ts +7 -0
- package/dist/rap/kernel.js +287 -0
- package/dist/rap/kernel.js.map +1 -0
- package/dist/rap/runtime.d.ts +84 -0
- package/dist/rap/runtime.js +128 -0
- package/dist/rap/runtime.js.map +1 -0
- package/dist/rap/transaction.d.ts +227 -0
- package/dist/rap/transaction.js +1385 -0
- package/dist/rap/transaction.js.map +1 -0
- package/dist/rap/types.d.ts +74 -0
- package/dist/rap/types.js +25 -0
- package/dist/rap/types.js.map +1 -0
- package/dist/server.d.ts +34 -0
- package/dist/server.js +114 -0
- package/dist/server.js.map +1 -0
- package/dist/ui/plugin.d.ts +14 -0
- package/dist/ui/plugin.js +47 -0
- package/dist/ui/plugin.js.map +1 -0
- package/dist/ui/resources.d.ts +22 -0
- package/dist/ui/resources.js +88 -0
- package/dist/ui/resources.js.map +1 -0
- package/dist/ui/variants.d.ts +25 -0
- package/dist/ui/variants.js +68 -0
- package/dist/ui/variants.js.map +1 -0
- package/dist/values.d.ts +43 -0
- package/dist/values.js +367 -0
- package/dist/values.js.map +1 -0
- package/package.json +60 -3
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser sessions over OIDC (PLAN.md §6.8): authorization code flow with PKCE, the user kept in
|
|
3
|
+
* a signed, HttpOnly cookie (no server-side store). API clients keep using bearer tokens.
|
|
4
|
+
*
|
|
5
|
+
* Routes: GET /auth/login?returnTo=…, GET /auth/callback, GET /auth/logout, GET /auth/me.
|
|
6
|
+
* The discovery document may be fetched from an internal URL (`discoveryUrl`) while the tokens
|
|
7
|
+
* name the public issuer: the usual setup of Keycloak in docker-compose.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
10
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
11
|
+
import { AuthenticationError } from "./auth.js";
|
|
12
|
+
export const SESSION_COOKIE = "rapt_session";
|
|
13
|
+
const STATE_COOKIE = "rapt_oidc";
|
|
14
|
+
/** The ID token of the login, kept for the logout (`id_token_hint`: no confirmation page at the provider). */
|
|
15
|
+
const ID_TOKEN_COOKIE = "rapt_idt";
|
|
16
|
+
const b64 = (data) => data.toString("base64url");
|
|
17
|
+
/** Signed values: base64url(JSON) + "." + HMAC-SHA256. */
|
|
18
|
+
class Signer {
|
|
19
|
+
secret;
|
|
20
|
+
constructor(secret) {
|
|
21
|
+
this.secret = secret;
|
|
22
|
+
if (secret.length < 32) {
|
|
23
|
+
throw new Error("the session secret needs at least 32 characters");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
sign(value) {
|
|
27
|
+
const body = b64(Buffer.from(JSON.stringify(value)));
|
|
28
|
+
return `${body}.${b64(createHmac("sha256", this.secret).update(body).digest())}`;
|
|
29
|
+
}
|
|
30
|
+
verify(signed) {
|
|
31
|
+
if (signed === undefined) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const dot = signed.lastIndexOf(".");
|
|
35
|
+
if (dot < 0) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const body = signed.slice(0, dot);
|
|
39
|
+
const expected = Buffer.from(b64(createHmac("sha256", this.secret).update(body).digest()));
|
|
40
|
+
const given = Buffer.from(signed.slice(dot + 1));
|
|
41
|
+
if (expected.length !== given.length || !timingSafeEqual(expected, given)) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const value = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
|
|
46
|
+
return typeof value.exp === "number" && value.exp * 1000 < Date.now() ? undefined : value;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function signedSession(signer, user, maxAge) {
|
|
54
|
+
const session = {
|
|
55
|
+
user: {
|
|
56
|
+
id: user.id,
|
|
57
|
+
abapName: user.abapName,
|
|
58
|
+
roles: user.roles,
|
|
59
|
+
authenticatedBy: "session",
|
|
60
|
+
...(user.name === undefined ? {} : { name: user.name }),
|
|
61
|
+
...(user.email === undefined ? {} : { email: user.email }),
|
|
62
|
+
...(user.attributes === undefined ? {} : { attributes: user.attributes }),
|
|
63
|
+
},
|
|
64
|
+
sid: b64(randomBytes(16)),
|
|
65
|
+
exp: Math.floor(Date.now() / 1000) + maxAge,
|
|
66
|
+
};
|
|
67
|
+
return signer.sign(session);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The value of a session cookie for a user, signed with the secret of the sessions: what the
|
|
71
|
+
* login callback sets. For the tests, and the tools that open a session for a known user.
|
|
72
|
+
*/
|
|
73
|
+
export function signSession(user, secret, maxAge = 8 * 3600) {
|
|
74
|
+
return signedSession(new Signer(secret), user, maxAge);
|
|
75
|
+
}
|
|
76
|
+
export function parseCookies(header) {
|
|
77
|
+
const cookies = {};
|
|
78
|
+
for (const part of (header ?? "").split(";")) {
|
|
79
|
+
const i = part.indexOf("=");
|
|
80
|
+
if (i > 0) {
|
|
81
|
+
cookies[part.slice(0, i).trim()] = decodeURIComponent(part.slice(i + 1).trim());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return cookies;
|
|
85
|
+
}
|
|
86
|
+
export class OidcSessions {
|
|
87
|
+
authenticator;
|
|
88
|
+
options;
|
|
89
|
+
signer;
|
|
90
|
+
metadataPromise;
|
|
91
|
+
jwks;
|
|
92
|
+
secure;
|
|
93
|
+
maxAge;
|
|
94
|
+
constructor(authenticator, options) {
|
|
95
|
+
this.authenticator = authenticator;
|
|
96
|
+
this.options = options;
|
|
97
|
+
this.signer = new Signer(options.session.secret);
|
|
98
|
+
this.secure = options.session.baseUrl.startsWith("https:");
|
|
99
|
+
this.maxAge = options.session.maxAge ?? 8 * 3600;
|
|
100
|
+
if (options.jwks !== undefined) {
|
|
101
|
+
this.jwks = options.jwks;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
metadata() {
|
|
105
|
+
this.metadataPromise ??= (async () => {
|
|
106
|
+
const base = this.options.discoveryUrl ?? this.options.issuer;
|
|
107
|
+
const url = base.includes(".well-known") ? base : new URL(".well-known/openid-configuration", base.endsWith("/") ? base : `${base}/`).href;
|
|
108
|
+
const response = await fetch(url);
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new AuthenticationError(`OIDC discovery failed (${response.status})`, 503);
|
|
111
|
+
}
|
|
112
|
+
return (await response.json());
|
|
113
|
+
})();
|
|
114
|
+
this.metadataPromise.catch(() => (this.metadataPromise = undefined));
|
|
115
|
+
return this.metadataPromise;
|
|
116
|
+
}
|
|
117
|
+
cookie(name, value, maxAge) {
|
|
118
|
+
return `${name}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${maxAge}${this.secure ? "; Secure" : ""}`;
|
|
119
|
+
}
|
|
120
|
+
redirectUri() {
|
|
121
|
+
return new URL("auth/callback", this.options.session.baseUrl.endsWith("/") ? this.options.session.baseUrl : `${this.options.session.baseUrl}/`).href;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The user of a session cookie; undefined without a valid session. The session may have been
|
|
125
|
+
* opened by another application sharing the secret (a launchpad, D37): the role required by
|
|
126
|
+
* this one is checked at each request (AuthenticationError 403 without it).
|
|
127
|
+
*/
|
|
128
|
+
user(request) {
|
|
129
|
+
const session = this.signer.verify(parseCookies(request.headers.cookie)[SESSION_COOKIE]);
|
|
130
|
+
if (session === undefined) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const required = this.options.requiredRole;
|
|
134
|
+
if (required !== undefined && !session.user.roles.includes(required)) {
|
|
135
|
+
throw new AuthenticationError(`the role ${required} is required`, 403);
|
|
136
|
+
}
|
|
137
|
+
return { ...session.user, authenticatedBy: "session", session: session.sid };
|
|
138
|
+
}
|
|
139
|
+
/** `/auth/login?returnTo=…` for the current page. */
|
|
140
|
+
loginUrl(returnTo) {
|
|
141
|
+
return `/auth/login?returnTo=${encodeURIComponent(returnTo)}`;
|
|
142
|
+
}
|
|
143
|
+
register(app) {
|
|
144
|
+
app.get("/auth/login", async (request, reply) => this.login(request, reply));
|
|
145
|
+
app.get("/auth/callback", async (request, reply) => this.callback(request, reply));
|
|
146
|
+
app.get("/auth/logout", async (request, reply) => this.logout(request, reply));
|
|
147
|
+
app.get("/auth/me", async (request, reply) => {
|
|
148
|
+
let user;
|
|
149
|
+
try {
|
|
150
|
+
user = this.user(request);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return reply.status(error instanceof AuthenticationError ? error.status : 401).send({ authenticated: true, error: error.message });
|
|
154
|
+
}
|
|
155
|
+
return user === undefined ? reply.status(401).send({ authenticated: false }) : { authenticated: true, id: user.id, name: user.name, roles: user.roles };
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async login(request, reply) {
|
|
159
|
+
const metadata = await this.metadata();
|
|
160
|
+
const query = request.query;
|
|
161
|
+
const returnTo = typeof query.returnTo === "string" && query.returnTo.startsWith("/") && !query.returnTo.startsWith("//") ? query.returnTo : "/";
|
|
162
|
+
const state = b64(randomBytes(24));
|
|
163
|
+
const nonce = b64(randomBytes(24));
|
|
164
|
+
const verifier = b64(randomBytes(32));
|
|
165
|
+
const challenge = b64(createHash("sha256").update(verifier).digest());
|
|
166
|
+
const url = new URL(metadata.authorization_endpoint);
|
|
167
|
+
url.searchParams.set("response_type", "code");
|
|
168
|
+
url.searchParams.set("client_id", this.options.session.clientId);
|
|
169
|
+
url.searchParams.set("redirect_uri", this.redirectUri());
|
|
170
|
+
url.searchParams.set("scope", this.options.session.scopes ?? "openid profile email");
|
|
171
|
+
url.searchParams.set("state", state);
|
|
172
|
+
url.searchParams.set("nonce", nonce);
|
|
173
|
+
url.searchParams.set("code_challenge", challenge);
|
|
174
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
175
|
+
reply.header("Set-Cookie", this.cookie(STATE_COOKIE, this.signer.sign({ state, nonce, verifier, returnTo, exp: Math.floor(Date.now() / 1000) + 600 }), 600));
|
|
176
|
+
return reply.redirect(url.href);
|
|
177
|
+
}
|
|
178
|
+
async callback(request, reply) {
|
|
179
|
+
const query = request.query;
|
|
180
|
+
const pending = this.signer.verify(parseCookies(request.headers.cookie)[STATE_COOKIE]);
|
|
181
|
+
if (query.error !== undefined) {
|
|
182
|
+
return reply.status(401).type("text/plain").send(`Login failed: ${query.error_description ?? query.error}`);
|
|
183
|
+
}
|
|
184
|
+
if (pending === undefined || query.state !== pending.state || typeof query.code !== "string") {
|
|
185
|
+
return reply.status(400).type("text/plain").send("Login failed: invalid or expired state, start again");
|
|
186
|
+
}
|
|
187
|
+
const metadata = await this.metadata();
|
|
188
|
+
const body = new URLSearchParams({
|
|
189
|
+
grant_type: "authorization_code",
|
|
190
|
+
code: query.code,
|
|
191
|
+
redirect_uri: this.redirectUri(),
|
|
192
|
+
client_id: this.options.session.clientId,
|
|
193
|
+
code_verifier: pending.verifier,
|
|
194
|
+
});
|
|
195
|
+
const headers = { "content-type": "application/x-www-form-urlencoded", accept: "application/json" };
|
|
196
|
+
if (this.options.session.clientSecret !== undefined) {
|
|
197
|
+
headers["authorization"] = `Basic ${Buffer.from(`${encodeURIComponent(this.options.session.clientId)}:${encodeURIComponent(this.options.session.clientSecret)}`).toString("base64")}`;
|
|
198
|
+
}
|
|
199
|
+
const response = await fetch(metadata.token_endpoint, { method: "POST", headers, body });
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
return reply.status(401).type("text/plain").send(`Login failed: the token endpoint answered ${response.status}`);
|
|
202
|
+
}
|
|
203
|
+
const tokens = (await response.json());
|
|
204
|
+
if (tokens.id_token === undefined) {
|
|
205
|
+
return reply.status(401).type("text/plain").send("Login failed: no ID token");
|
|
206
|
+
}
|
|
207
|
+
this.jwks ??= createRemoteJWKSet(new URL(metadata.jwks_uri));
|
|
208
|
+
let user;
|
|
209
|
+
try {
|
|
210
|
+
const { payload } = await jwtVerify(tokens.id_token, this.jwks, { issuer: this.options.issuer, audience: this.options.session.clientId });
|
|
211
|
+
if (payload["nonce"] !== pending.nonce) {
|
|
212
|
+
throw new AuthenticationError("the ID token has another nonce");
|
|
213
|
+
}
|
|
214
|
+
user = this.authenticator.userFromClaims(payload, "session");
|
|
215
|
+
// roles and attributes: Keycloak puts the realm roles (and mapped attributes) in the access token
|
|
216
|
+
if (tokens.access_token !== undefined && (user.roles.length === 0 || (this.options.attributeClaims ?? []).some((c) => user.attributes?.[c] === undefined))) {
|
|
217
|
+
try {
|
|
218
|
+
const access = await jwtVerify(tokens.access_token, this.jwks, { issuer: this.options.issuer });
|
|
219
|
+
const fromAccess = this.authenticator.userFromClaims(access.payload, "session");
|
|
220
|
+
const attributes = { ...(fromAccess.attributes ?? {}), ...(user.attributes ?? {}) };
|
|
221
|
+
user = { ...user, roles: user.roles.length === 0 ? fromAccess.roles : user.roles, ...(Object.keys(attributes).length === 0 ? {} : { attributes }) };
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// an opaque access token: the roles and claims of the ID token
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
return reply.status(error instanceof AuthenticationError ? error.status : 401).type("text/plain").send(`Login failed: ${error.message}`);
|
|
230
|
+
}
|
|
231
|
+
reply.header("Set-Cookie", [this.cookie(SESSION_COOKIE, signedSession(this.signer, user, this.maxAge), this.maxAge), this.cookie(STATE_COOKIE, "", 0), this.cookie(ID_TOKEN_COOKIE, tokens.id_token, this.maxAge)]);
|
|
232
|
+
return reply.redirect(pending.returnTo);
|
|
233
|
+
}
|
|
234
|
+
async logout(request, reply) {
|
|
235
|
+
const idToken = parseCookies(request.headers.cookie)[ID_TOKEN_COOKIE];
|
|
236
|
+
reply.header("Set-Cookie", [this.cookie(SESSION_COOKIE, "", 0), this.cookie(ID_TOKEN_COOKIE, "", 0)]);
|
|
237
|
+
let target = "/";
|
|
238
|
+
try {
|
|
239
|
+
const metadata = await this.metadata();
|
|
240
|
+
if (metadata.end_session_endpoint !== undefined) {
|
|
241
|
+
const url = new URL(metadata.end_session_endpoint);
|
|
242
|
+
url.searchParams.set("client_id", this.options.session.clientId);
|
|
243
|
+
url.searchParams.set("post_logout_redirect_uri", this.options.session.baseUrl);
|
|
244
|
+
// the provider ends its session without asking (OIDC RP-Initiated Logout, even with an expired ID token)
|
|
245
|
+
if (idToken !== undefined && /^[\w-]+\.[\w-]+\.[\w-]+$/.test(idToken)) {
|
|
246
|
+
url.searchParams.set("id_token_hint", idToken);
|
|
247
|
+
}
|
|
248
|
+
target = url.href;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// the provider is not reachable: local logout only
|
|
253
|
+
}
|
|
254
|
+
return reply.redirect(target);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** The authenticated user of a request. */
|
|
2
|
+
export interface User {
|
|
3
|
+
/** Identifier from the identity provider (or the development user). */
|
|
4
|
+
id: string;
|
|
5
|
+
/** User name in ABAP form: upper case, at most 12 characters (sy-uname, CreatedBy…). */
|
|
6
|
+
abapName: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
roles: string[];
|
|
10
|
+
/** Claims of the token the authorizations read (`{claim:agency}` in a role): claim → values. */
|
|
11
|
+
attributes?: Record<string, string[]>;
|
|
12
|
+
authenticatedBy: "development" | "bearer" | "session";
|
|
13
|
+
/** Browser sessions: the session identifier (the CSRF token is bound to it). */
|
|
14
|
+
session?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function abapUserName(id: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The user of the development mode (AUTH_MODE=none). Without given roles (`*`) it has every
|
|
19
|
+
* authorization, as a developer has SAP_ALL in a development system.
|
|
20
|
+
*/
|
|
21
|
+
export declare function developmentUser(id?: string, roles?: string[], attributes?: Record<string, string[]>): User;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The authenticated user of a request. */
|
|
2
|
+
export function abapUserName(id) {
|
|
3
|
+
return id.toUpperCase().slice(0, 12);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The user of the development mode (AUTH_MODE=none). Without given roles (`*`) it has every
|
|
7
|
+
* authorization, as a developer has SAP_ALL in a development system.
|
|
8
|
+
*/
|
|
9
|
+
export function developmentUser(id = "DEVELOPER", roles, attributes) {
|
|
10
|
+
return { id, abapName: abapUserName(id), roles: roles ?? ["*"], authenticatedBy: "development", ...(attributes === undefined ? {} : { attributes }) };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=user.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/auth/user.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAiB3C,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,GAAG,WAAW,EAAE,KAAgB,EAAE,UAAqC;IACvG,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;AACxJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database access: Kysely over node-postgres, or over PGlite (tests, local development).
|
|
3
|
+
* Dates, time stamps, numerics and INT8 are read as strings so that no precision is lost
|
|
4
|
+
* (decision D16); the session time zone is UTC.
|
|
5
|
+
*/
|
|
6
|
+
import { Kysely, type Dialect } from "kysely";
|
|
7
|
+
export type Database = Kysely<Record<string, Record<string, unknown>>>;
|
|
8
|
+
/** PGlite parsers keeping the PostgreSQL text form (pass as `parsers` to `new PGlite`). */
|
|
9
|
+
export declare const PGLITE_PARSERS: Record<number, (value: string) => unknown>;
|
|
10
|
+
export declare function createPostgresDatabase(connectionString: string, options?: {
|
|
11
|
+
max?: number;
|
|
12
|
+
ca?: string;
|
|
13
|
+
}): Database;
|
|
14
|
+
export declare function createDatabase(dialect: Dialect): Database;
|
|
15
|
+
/**
|
|
16
|
+
* Runs `fn` in a savepoint of the transaction `db`: when it fails (a lock that is not available,
|
|
17
|
+
* a SELECT of the ABAP code), PostgreSQL would otherwise refuse every further statement of the
|
|
18
|
+
* transaction. Rolled back to the savepoint, the transaction goes on.
|
|
19
|
+
*/
|
|
20
|
+
export declare function withSavepoint<T, DB>(db: Kysely<DB>, fn: () => Promise<T>): Promise<T>;
|
|
21
|
+
/**
|
|
22
|
+
* The statements of an SQL script: split at the semicolons outside literals, quoted identifiers,
|
|
23
|
+
* dollar-quoted bodies (PL/pgSQL functions) and comments.
|
|
24
|
+
*/
|
|
25
|
+
export declare function splitStatements(script: string): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Applies the generated schema (idempotent) in one transaction, one statement at a time: the
|
|
28
|
+
* extended protocol of PGlite (and of prepared statements) takes one command per query.
|
|
29
|
+
*/
|
|
30
|
+
export declare function applySchema(db: Database, schema: string): Promise<void>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database access: Kysely over node-postgres, or over PGlite (tests, local development).
|
|
3
|
+
* Dates, time stamps, numerics and INT8 are read as strings so that no precision is lost
|
|
4
|
+
* (decision D16); the session time zone is UTC.
|
|
5
|
+
*/
|
|
6
|
+
import { Kysely, PostgresDialect, sql } from "kysely";
|
|
7
|
+
import pg from "pg";
|
|
8
|
+
const DATE = 1082;
|
|
9
|
+
const TIME = 1083;
|
|
10
|
+
const TIMESTAMP = 1114;
|
|
11
|
+
const TIMESTAMPTZ = 1184;
|
|
12
|
+
const NUMERIC = 1700;
|
|
13
|
+
const INT8 = 20;
|
|
14
|
+
const asString = (value) => value;
|
|
15
|
+
/** PGlite parsers keeping the PostgreSQL text form (pass as `parsers` to `new PGlite`). */
|
|
16
|
+
export const PGLITE_PARSERS = {
|
|
17
|
+
[DATE]: asString,
|
|
18
|
+
[TIME]: asString,
|
|
19
|
+
[TIMESTAMP]: asString,
|
|
20
|
+
[TIMESTAMPTZ]: asString,
|
|
21
|
+
[NUMERIC]: asString,
|
|
22
|
+
[INT8]: asString,
|
|
23
|
+
};
|
|
24
|
+
export function createPostgresDatabase(connectionString, options = {}) {
|
|
25
|
+
const pool = new pg.Pool({
|
|
26
|
+
connectionString,
|
|
27
|
+
// the certificate of the database server (DATABASE_CA, a bound service on Cloud Foundry, D50)
|
|
28
|
+
...(options.ca === undefined || options.ca === "" ? {} : { ssl: { ca: options.ca, rejectUnauthorized: true } }),
|
|
29
|
+
max: options.max ?? 10,
|
|
30
|
+
options: "-c TimeZone=UTC",
|
|
31
|
+
types: {
|
|
32
|
+
getTypeParser: ((oid, format) => {
|
|
33
|
+
if (oid === DATE || oid === TIME || oid === TIMESTAMP || oid === TIMESTAMPTZ || oid === NUMERIC || oid === INT8) {
|
|
34
|
+
return asString;
|
|
35
|
+
}
|
|
36
|
+
return format === undefined ? pg.types.getTypeParser(oid) : pg.types.getTypeParser(oid, format);
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return new Kysely({ dialect: new PostgresDialect({ pool }) });
|
|
41
|
+
}
|
|
42
|
+
export function createDatabase(dialect) {
|
|
43
|
+
return new Kysely({ dialect });
|
|
44
|
+
}
|
|
45
|
+
let savepoints = 0;
|
|
46
|
+
/**
|
|
47
|
+
* Runs `fn` in a savepoint of the transaction `db`: when it fails (a lock that is not available,
|
|
48
|
+
* a SELECT of the ABAP code), PostgreSQL would otherwise refuse every further statement of the
|
|
49
|
+
* transaction. Rolled back to the savepoint, the transaction goes on.
|
|
50
|
+
*/
|
|
51
|
+
export async function withSavepoint(db, fn) {
|
|
52
|
+
const name = `rapt_${++savepoints}`;
|
|
53
|
+
await sql.raw(`SAVEPOINT ${name}`).execute(db);
|
|
54
|
+
let result;
|
|
55
|
+
try {
|
|
56
|
+
result = await fn();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
await sql.raw(`ROLLBACK TO SAVEPOINT ${name}`).execute(db);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
await sql.raw(`RELEASE SAVEPOINT ${name}`).execute(db);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The statements of an SQL script: split at the semicolons outside literals, quoted identifiers,
|
|
67
|
+
* dollar-quoted bodies (PL/pgSQL functions) and comments.
|
|
68
|
+
*/
|
|
69
|
+
export function splitStatements(script) {
|
|
70
|
+
const statements = [];
|
|
71
|
+
let start = 0;
|
|
72
|
+
let i = 0;
|
|
73
|
+
const push = (end) => {
|
|
74
|
+
const text = script.slice(start, end).trim();
|
|
75
|
+
if (text.replace(/--[^\n]*/g, "").trim() !== "") {
|
|
76
|
+
statements.push(text);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
while (i < script.length) {
|
|
80
|
+
const c = script[i];
|
|
81
|
+
if (c === "'" || c === '"') {
|
|
82
|
+
// a literal or a quoted identifier: a doubled quote stays inside
|
|
83
|
+
i++;
|
|
84
|
+
while (i < script.length && !(script[i] === c && script[i + 1] !== c)) {
|
|
85
|
+
i += script[i] === c ? 2 : 1;
|
|
86
|
+
}
|
|
87
|
+
i++;
|
|
88
|
+
}
|
|
89
|
+
else if (c === "-" && script[i + 1] === "-") {
|
|
90
|
+
const end = script.indexOf("\n", i);
|
|
91
|
+
i = end < 0 ? script.length : end + 1;
|
|
92
|
+
}
|
|
93
|
+
else if (c === "/" && script[i + 1] === "*") {
|
|
94
|
+
const end = script.indexOf("*/", i + 2);
|
|
95
|
+
i = end < 0 ? script.length : end + 2;
|
|
96
|
+
}
|
|
97
|
+
else if (c === "$") {
|
|
98
|
+
const tag = /^\$[A-Za-z_]*\$/.exec(script.slice(i))?.[0];
|
|
99
|
+
if (tag === undefined) {
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const end = script.indexOf(tag, i + tag.length);
|
|
104
|
+
i = end < 0 ? script.length : end + tag.length;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (c === ";") {
|
|
108
|
+
push(i);
|
|
109
|
+
i++;
|
|
110
|
+
start = i;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
push(script.length);
|
|
117
|
+
return statements;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Applies the generated schema (idempotent) in one transaction, one statement at a time: the
|
|
121
|
+
* extended protocol of PGlite (and of prepared statements) takes one command per query.
|
|
122
|
+
*/
|
|
123
|
+
export async function applySchema(db, schema) {
|
|
124
|
+
await db.transaction().execute(async (trx) => {
|
|
125
|
+
await sql.raw("SET LOCAL TIME ZONE 'UTC'").execute(trx);
|
|
126
|
+
for (const statement of splitStatements(schema)) {
|
|
127
|
+
await sql.raw(statement).execute(trx);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed data (decision D42): `db/seed.json` (table → rows) and `db/seed.sql`, written by the
|
|
3
|
+
* compiler from `rapt/seed.json` and `rapt/seed.sql`. They are loaded when every table of the
|
|
4
|
+
* application is empty — its first start — if `SEED=auto` (`rapt dev` sets it).
|
|
5
|
+
*/
|
|
6
|
+
import { type Model } from "@open-rap/model";
|
|
7
|
+
import { type Database } from "./database.js";
|
|
8
|
+
/** Loads the seed of the application folder `dir`; returns the number of rows inserted, or undefined when not loaded. */
|
|
9
|
+
export declare function applySeed(db: Database, model: Model, dir: string): Promise<number | undefined>;
|
package/dist/db/seed.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed data (decision D42): `db/seed.json` (table → rows) and `db/seed.sql`, written by the
|
|
3
|
+
* compiler from `rapt/seed.json` and `rapt/seed.sql`. They are loaded when every table of the
|
|
4
|
+
* application is empty — its first start — if `SEED=auto` (`rapt dev` sets it).
|
|
5
|
+
*/
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { sql } from "kysely";
|
|
10
|
+
import { isUuid } from "@open-rap/model";
|
|
11
|
+
import { splitStatements } from "./database.js";
|
|
12
|
+
/** Loads the seed of the application folder `dir`; returns the number of rows inserted, or undefined when not loaded. */
|
|
13
|
+
export async function applySeed(db, model, dir) {
|
|
14
|
+
const jsonFile = path.join(dir, "db", "seed.json");
|
|
15
|
+
const sqlFile = path.join(dir, "db", "seed.sql");
|
|
16
|
+
if (!existsSync(jsonFile) && !existsSync(sqlFile)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
for (const table of model.tables.filter((t) => t.standard !== true)) {
|
|
20
|
+
const row = await db.selectFrom(table.name).select(sql `1`.as("one")).limit(1).executeTakeFirst();
|
|
21
|
+
if (row !== undefined) {
|
|
22
|
+
return undefined; // not the first start
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const json = existsSync(jsonFile) ? JSON.parse(readFileSync(jsonFile, "utf8")) : {};
|
|
26
|
+
let count = 0;
|
|
27
|
+
await db.transaction().execute(async (trx) => {
|
|
28
|
+
await sql.raw("SET LOCAL TIME ZONE 'UTC'").execute(trx);
|
|
29
|
+
for (const [name, rows] of Object.entries(json)) {
|
|
30
|
+
const table = model.tables.find((t) => t.name === name);
|
|
31
|
+
if (table === undefined || rows.length === 0) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// a UUID key left out is drawn at random
|
|
35
|
+
const uuidKeys = table.columns.filter((c) => c.key && !c.client && isUuid(c.type)).map((c) => c.name);
|
|
36
|
+
const numc = table.columns.filter((c) => c.type.kind === "numc" && c.type.length !== undefined);
|
|
37
|
+
const values = rows.map((row) => {
|
|
38
|
+
const filled = { ...row };
|
|
39
|
+
// NUMC fields are stored with their leading zeros, as ABAP writes them
|
|
40
|
+
for (const column of numc) {
|
|
41
|
+
const value = filled[column.name];
|
|
42
|
+
if ((typeof value === "string" || typeof value === "number") && /^\d+$/.test(String(value))) {
|
|
43
|
+
filled[column.name] = String(value).padStart(column.type.length ?? 0, "0");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const key of uuidKeys) {
|
|
47
|
+
if (filled[key] === undefined || filled[key] === null || filled[key] === "")
|
|
48
|
+
filled[key] = randomUUID();
|
|
49
|
+
}
|
|
50
|
+
return filled;
|
|
51
|
+
});
|
|
52
|
+
await trx.insertInto(name).values(values).execute();
|
|
53
|
+
count += values.length;
|
|
54
|
+
}
|
|
55
|
+
if (existsSync(sqlFile)) {
|
|
56
|
+
for (const statement of splitStatements(readFileSync(sqlFile, "utf8"))) {
|
|
57
|
+
await sql.raw(statement).execute(trx);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return count;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=seed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/db/seed.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Runtime of the applications generated by Open RAP Runtime. */
|
|
2
|
+
export declare const RUNTIME_VERSION = "0.1.0";
|
|
3
|
+
export { createApp, type AppOptions, type AppServices } from "./app.js";
|
|
4
|
+
export { Authenticator, AuthenticationError, type AuthOptions, type OidcAuthOptions } from "./auth/auth.js";
|
|
5
|
+
export { developmentUser, type User } from "./auth/user.js";
|
|
6
|
+
export { applySeed } from "./db/seed.js";
|
|
7
|
+
export { applySchema, createDatabase, createPostgresDatabase, PGLITE_PARSERS, type Database } from "./db/database.js";
|
|
8
|
+
export { ODataError } from "./odata/errors.js";
|
|
9
|
+
export { ODataHandler, type HandlerContext, type ODataRequest, type ODataResponse, type WriteHandler } from "./odata/handler.js";
|
|
10
|
+
export { parseBatch, serializeBatch } from "./odata/batch.js";
|
|
11
|
+
export { ReadEngine } from "./odata/read.js";
|
|
12
|
+
export { ServiceRuntime } from "./odata/service.js";
|
|
13
|
+
export { parseExpand, parseFilter, parseOrderby, parseSelect } from "./odata/uri/parser.js";
|
|
14
|
+
export * from "./values.js";
|
|
15
|
+
export { start, type RunningServer, type StartOptions } from "./server.js";
|
|
16
|
+
export { RapRuntime } from "./rap/runtime.js";
|
|
17
|
+
export { OidcSessions, signSession } from "./auth/session.js";
|
|
18
|
+
export { createLaunchpad, launchpadView, startLaunchpad, type LaunchpadOptions, type LaunchpadView, type RunningLaunchpad, type StartLaunchpadOptions } from "./launchpad/server.js";
|
|
19
|
+
export { rewriteLocation } from "./launchpad/proxy.js";
|
|
20
|
+
export { boundPostgres, platformEnvironment } from "./platform.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Runtime of the applications generated by Open RAP Runtime. */
|
|
2
|
+
export const RUNTIME_VERSION = "0.1.0";
|
|
3
|
+
export { createApp } from "./app.js";
|
|
4
|
+
export { Authenticator, AuthenticationError } from "./auth/auth.js";
|
|
5
|
+
export { developmentUser } from "./auth/user.js";
|
|
6
|
+
export { applySeed } from "./db/seed.js";
|
|
7
|
+
export { applySchema, createDatabase, createPostgresDatabase, PGLITE_PARSERS } from "./db/database.js";
|
|
8
|
+
export { ODataError } from "./odata/errors.js";
|
|
9
|
+
export { ODataHandler } from "./odata/handler.js";
|
|
10
|
+
export { parseBatch, serializeBatch } from "./odata/batch.js";
|
|
11
|
+
export { ReadEngine } from "./odata/read.js";
|
|
12
|
+
export { ServiceRuntime } from "./odata/service.js";
|
|
13
|
+
export { parseExpand, parseFilter, parseOrderby, parseSelect } from "./odata/uri/parser.js";
|
|
14
|
+
export * from "./values.js";
|
|
15
|
+
export { start } from "./server.js";
|
|
16
|
+
export { RapRuntime } from "./rap/runtime.js";
|
|
17
|
+
export { OidcSessions, signSession } from "./auth/session.js";
|
|
18
|
+
export { createLaunchpad, launchpadView, startLaunchpad } from "./launchpad/server.js";
|
|
19
|
+
export { rewriteLocation } from "./launchpad/proxy.js";
|
|
20
|
+
export { boundPostgres, platformEnvironment } from "./platform.js";
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAqC,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAA0C,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,eAAe,EAAa,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB,EAAE,cAAc,EAAiB,MAAM,kBAAkB,CAAC;AACtH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAiF,MAAM,oBAAoB,CAAC;AACjI,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC5F,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAyC,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAgG,MAAM,uBAAuB,CAAC;AACrL,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The development launchpad of `rapt dev` (decision D49): at `/`, a launchpad with the application
|
|
3
|
+
* and the development tools (documentation, $metadata, MCP tools), served by the application
|
|
4
|
+
* itself. Its configuration is `home/launchpad.json` of the development build; `/launchpad/config`
|
|
5
|
+
* gives the application and the documentation app the shell bar of the launchpad.
|
|
6
|
+
*/
|
|
7
|
+
import type { FastifyInstance } from "fastify";
|
|
8
|
+
import type { LaunchpadModel } from "@open-rap/model";
|
|
9
|
+
import type { Authenticator } from "../auth/auth.js";
|
|
10
|
+
export declare function registerDevLaunchpad(app: FastifyInstance, options: {
|
|
11
|
+
dir: string;
|
|
12
|
+
config: LaunchpadModel;
|
|
13
|
+
authenticator: Authenticator;
|
|
14
|
+
}): void;
|