@getstrata/bootstrap 1.0.0 → 1.0.2
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/CHANGELOG.md +27 -12
- package/README.md +32 -12
- package/dist/bootstrap/web/server.d.ts +3 -3
- package/dist/entries/secretsGuard.js +39 -7
- package/dist/entries/web/server.js +8 -2
- package/dist/entries/web/session.js +10 -4
- package/dist/index.js +57 -13
- package/package.json +7 -9
- package/dist/_.._/_.._/index.html +0 -174
- package/dist/bootstrap/createRoutes.d.ts +0 -3
- package/dist/bootstrap/dogfoodApp.d.ts +0 -7
- package/dist/bootstrap/preloadModules.d.ts +0 -1
- package/dist/bootstrap/routes.d.ts +0 -3
- package/dist/entries/createRoutes.js +0 -801
- package/dist/index-a3tzxvag.js +0 -0
|
@@ -1,801 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var __jsonParse = (a) => JSON.parse(a);
|
|
3
|
-
|
|
4
|
-
// ../../src/bootstrap/createRoutes.ts
|
|
5
|
-
import { jsonResponse as jsonResponse3 } from "@getstrata/core/http/response";
|
|
6
|
-
import { isSpaEnabled as isSpaEnabled2, isViewsEnabled as isViewsEnabled4 } from "@getstrata/core/runtime/frontendMode";
|
|
7
|
-
import { notFoundHtmlResponse as notFoundHtmlResponse2 } from "@getstrata/core/view";
|
|
8
|
-
|
|
9
|
-
// ../../index.html
|
|
10
|
-
var strata_default = __jsonParse("{\"index\":\"_.._/_.._/index.html\",\"files\":[{\"input\":\"../../index.html\",\"path\":\"./index-a3tzxvag.js\",\"loader\":\"js\",\"isEntry\":true,\"headers\":{\"etag\":\"qoOafz0bKrA\",\"content-type\":\"text/javascript;charset=utf-8\"}},{\"input\":\"../../index.html\",\"path\":\"_.._/_.._/index.html\",\"loader\":\"html\",\"isEntry\":true,\"headers\":{\"etag\":\"g_F9s_nobLw\",\"content-type\":\"text/html;charset=utf-8\"}}]}");
|
|
11
|
-
|
|
12
|
-
// ../../src/config/app.ts
|
|
13
|
-
var appConfig = {
|
|
14
|
-
name: process.env.APP_NAME?.trim() || "Strata",
|
|
15
|
-
env: process.env.APP_ENV ?? "local",
|
|
16
|
-
debug: (process.env.APP_DEBUG ?? "true") !== "false",
|
|
17
|
-
url: process.env.APP_URL ?? "http://localhost:3000",
|
|
18
|
-
apiPrefix: process.env.API_PREFIX ?? "/api/v1"
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// ../../src/bootstrap/buildModuleRoutes.ts
|
|
22
|
-
import { conditionalJsonResponse } from "@getstrata/core/http/conditionalResponse";
|
|
23
|
-
import { applyMiddlewareToRoutes } from "@getstrata/core/http/middleware";
|
|
24
|
-
|
|
25
|
-
// ../../src/bootstrap/httpKernel.ts
|
|
26
|
-
import {
|
|
27
|
-
hasVerifiedEmail,
|
|
28
|
-
isEmailVerificationRequired
|
|
29
|
-
} from "@getstrata/core/auth/emailVerification";
|
|
30
|
-
import { createMembershipMiddleware } from "@getstrata/core/auth/membershipMiddleware";
|
|
31
|
-
import { resolveAbilityChecker } from "@getstrata/core/contracts/serviceTokens";
|
|
32
|
-
import { createAuthMiddleware } from "@getstrata/core/http/authMiddleware";
|
|
33
|
-
import { createAuthorizeMiddleware } from "@getstrata/core/http/authorizeMiddleware";
|
|
34
|
-
import { createBodySizeLimitMiddleware } from "@getstrata/core/http/bodySizeLimitMiddleware";
|
|
35
|
-
import { createCorsMiddleware } from "@getstrata/core/http/corsMiddleware";
|
|
36
|
-
import { createCsrfMiddleware } from "@getstrata/core/http/csrfMiddleware";
|
|
37
|
-
import { createFlashMiddleware } from "@getstrata/core/http/flashMiddleware";
|
|
38
|
-
import { createLoginThrottleMiddleware } from "@getstrata/core/http/loginThrottleMiddleware";
|
|
39
|
-
import { createMemoryThrottleMiddleware } from "@getstrata/core/http/memoryThrottleMiddleware";
|
|
40
|
-
import { createMetricsMiddleware } from "@getstrata/core/http/metricsMiddleware";
|
|
41
|
-
import { requestIdMiddleware } from "@getstrata/core/http/middleware";
|
|
42
|
-
import { createRequireAbilityMiddleware } from "@getstrata/core/http/requireAbilityMiddleware";
|
|
43
|
-
import { createRequireAuthMiddleware } from "@getstrata/core/http/requireAuthMiddleware";
|
|
44
|
-
import { createRequireGlobalAdminMiddleware } from "@getstrata/core/http/requireGlobalAdminMiddleware";
|
|
45
|
-
import { createRequirePasswordConfirmMiddleware } from "@getstrata/core/http/requirePasswordConfirmMiddleware";
|
|
46
|
-
import { createRequireVerifiedMiddleware } from "@getstrata/core/http/requireVerifiedMiddleware";
|
|
47
|
-
import { createRequireWebAuthMiddleware } from "@getstrata/core/http/requireWebAuthMiddleware";
|
|
48
|
-
import { withErrorHandling, withJsonErrorHandling } from "@getstrata/core/http/response";
|
|
49
|
-
import { withMiddleware } from "@getstrata/core/http/routeMiddleware";
|
|
50
|
-
import { createSecurityHeadersMiddleware } from "@getstrata/core/http/securityHeadersMiddleware";
|
|
51
|
-
import { createValidateSignatureMiddleware } from "@getstrata/core/http/signedUrl";
|
|
52
|
-
import { createThrottleMiddleware } from "@getstrata/core/http/throttleMiddleware";
|
|
53
|
-
import { createRequestLoggingMiddleware } from "@getstrata/core/logging/requestLoggingMiddleware";
|
|
54
|
-
import { isViewsEnabled } from "@getstrata/core/runtime/frontendMode";
|
|
55
|
-
import { isPublicReadsEnabled } from "@getstrata/core/security/publicReads";
|
|
56
|
-
import { createTenantMiddleware } from "@getstrata/core/tenant/tenantMiddleware";
|
|
57
|
-
import { createTracingMiddleware } from "@getstrata/core/tracing/tracingMiddleware";
|
|
58
|
-
|
|
59
|
-
// ../../src/bootstrap/config.ts
|
|
60
|
-
import {
|
|
61
|
-
CORE_ABILITY_CHECKER_TOKEN,
|
|
62
|
-
CORE_AUTH_TOKEN,
|
|
63
|
-
CORE_AUTH_USER_DIRECTORY_TOKEN,
|
|
64
|
-
CORE_CACHE_TOKEN,
|
|
65
|
-
CORE_CONFIG_TOKEN,
|
|
66
|
-
CORE_EVENT_BUS_TOKEN,
|
|
67
|
-
CORE_POLICY_GATE_TOKEN,
|
|
68
|
-
CORE_QUEUE_TOKEN,
|
|
69
|
-
CORE_TOKEN_SERVICE_TOKEN
|
|
70
|
-
} from "@getstrata/core/contracts/serviceTokens";
|
|
71
|
-
var APP_PORT_CONFIG_KEY = "app.port";
|
|
72
|
-
var CACHE_TTL_MS_CONFIG_KEY = "cache.ttlMs";
|
|
73
|
-
var CACHE_MAX_ENTRIES_CONFIG_KEY = "cache.maxEntries";
|
|
74
|
-
var CACHE_DRIVER_CONFIG_KEY = "cache.driver";
|
|
75
|
-
var REDIS_URL_CONFIG_KEY = "cache.redisUrl";
|
|
76
|
-
var DATABASE_URL_CONFIG_KEY = "database.url";
|
|
77
|
-
var AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
|
|
78
|
-
var DEFAULT_APP_PORT = 3000;
|
|
79
|
-
var DEFAULT_CACHE_TTL_MS = 3600000;
|
|
80
|
-
var DEFAULT_CACHE_MAX_ENTRIES = 100;
|
|
81
|
-
var DEFAULT_CACHE_DRIVER = "array";
|
|
82
|
-
var DEFAULT_API_TOKEN = "";
|
|
83
|
-
var DEFAULT_QUEUE_DRIVER = "sync";
|
|
84
|
-
|
|
85
|
-
// ../../src/bootstrap/rateLimit.ts
|
|
86
|
-
var LOCAL_LOGIN_RATE_LIMIT = {
|
|
87
|
-
maxAttempts: 100,
|
|
88
|
-
decaySeconds: 60
|
|
89
|
-
};
|
|
90
|
-
var PRODUCTION_LOGIN_RATE_LIMIT = {
|
|
91
|
-
maxAttempts: 5,
|
|
92
|
-
decaySeconds: 900
|
|
93
|
-
};
|
|
94
|
-
function isLocalAppEnv() {
|
|
95
|
-
return (process.env.APP_ENV ?? "local") === "local";
|
|
96
|
-
}
|
|
97
|
-
function parsePositiveInt(value, fallback) {
|
|
98
|
-
const parsed = Number(value);
|
|
99
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
100
|
-
return fallback;
|
|
101
|
-
}
|
|
102
|
-
return Math.trunc(parsed);
|
|
103
|
-
}
|
|
104
|
-
function parseWindowSeconds(secondsValue, msValue, fallback) {
|
|
105
|
-
if (secondsValue !== undefined && secondsValue.trim() !== "") {
|
|
106
|
-
return parsePositiveInt(secondsValue, fallback);
|
|
107
|
-
}
|
|
108
|
-
if (msValue !== undefined && msValue.trim() !== "") {
|
|
109
|
-
const parsedMs = Number(msValue);
|
|
110
|
-
if (Number.isFinite(parsedMs) && parsedMs > 0) {
|
|
111
|
-
return Math.max(1, Math.trunc(parsedMs / 1000));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return fallback;
|
|
115
|
-
}
|
|
116
|
-
function resolveLoginRateLimit() {
|
|
117
|
-
const defaults = isLocalAppEnv() ? LOCAL_LOGIN_RATE_LIMIT : PRODUCTION_LOGIN_RATE_LIMIT;
|
|
118
|
-
return {
|
|
119
|
-
maxAttempts: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
|
|
120
|
-
decaySeconds: parseWindowSeconds(process.env.LOGIN_RATE_LIMIT_WINDOW_SECONDS, process.env.LOGIN_RATE_LIMIT_WINDOW_MS, defaults.decaySeconds)
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
function resolveRegisterRateLimit() {
|
|
124
|
-
const defaults = isLocalAppEnv() ? { maxAttempts: 100, decaySeconds: 60 } : { maxAttempts: 10, decaySeconds: 60 };
|
|
125
|
-
return {
|
|
126
|
-
maxAttempts: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
|
|
127
|
-
decaySeconds: parseWindowSeconds(process.env.REGISTER_RATE_LIMIT_WINDOW_SECONDS, process.env.REGISTER_RATE_LIMIT_WINDOW_MS, defaults.decaySeconds)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ../../src/bootstrap/httpKernel.ts
|
|
132
|
-
class HttpKernel {
|
|
133
|
-
dependencies;
|
|
134
|
-
constructor(dependencies) {
|
|
135
|
-
this.dependencies = dependencies;
|
|
136
|
-
}
|
|
137
|
-
globalMiddleware() {
|
|
138
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
139
|
-
return [
|
|
140
|
-
createCorsMiddleware(),
|
|
141
|
-
createSecurityHeadersMiddleware(),
|
|
142
|
-
createBodySizeLimitMiddleware(),
|
|
143
|
-
createTracingMiddleware(),
|
|
144
|
-
createMetricsMiddleware(),
|
|
145
|
-
createRequestLoggingMiddleware(),
|
|
146
|
-
requestIdMiddleware,
|
|
147
|
-
createAuthMiddleware(auth),
|
|
148
|
-
createMembershipMiddleware(),
|
|
149
|
-
createTenantMiddleware()
|
|
150
|
-
];
|
|
151
|
-
}
|
|
152
|
-
group(name) {
|
|
153
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
154
|
-
switch (name) {
|
|
155
|
-
case "authenticated":
|
|
156
|
-
return [createRequireAuthMiddleware(auth)];
|
|
157
|
-
case "web":
|
|
158
|
-
return isViewsEnabled() ? [createFlashMiddleware(), createCsrfMiddleware()] : [];
|
|
159
|
-
case "api": {
|
|
160
|
-
if (!this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
|
|
161
|
-
return [];
|
|
162
|
-
}
|
|
163
|
-
const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
|
|
164
|
-
const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
|
|
165
|
-
if (!redisUrl) {
|
|
166
|
-
const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
|
|
167
|
-
return [
|
|
168
|
-
createMemoryThrottleMiddleware({
|
|
169
|
-
maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
|
|
170
|
-
decaySeconds: 60
|
|
171
|
-
})
|
|
172
|
-
];
|
|
173
|
-
}
|
|
174
|
-
const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
|
|
175
|
-
return [
|
|
176
|
-
createThrottleMiddleware({
|
|
177
|
-
redisUrl,
|
|
178
|
-
maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
|
|
179
|
-
decaySeconds: 60
|
|
180
|
-
})
|
|
181
|
-
];
|
|
182
|
-
}
|
|
183
|
-
default:
|
|
184
|
-
throw new Error(`Unknown middleware group "${name}".`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
wrap(groups, handler) {
|
|
188
|
-
const names = Array.isArray(groups) ? groups : [groups];
|
|
189
|
-
const middleware = names.flatMap((name) => this.group(name));
|
|
190
|
-
if (middleware.length === 0) {
|
|
191
|
-
return handler;
|
|
192
|
-
}
|
|
193
|
-
return withMiddleware(...middleware)(handler);
|
|
194
|
-
}
|
|
195
|
-
wrapApi(handler) {
|
|
196
|
-
return withJsonErrorHandling(this.wrap(["api", "authenticated"], handler));
|
|
197
|
-
}
|
|
198
|
-
wrapWeb(handler) {
|
|
199
|
-
return withErrorHandling(this.wrap("web", handler));
|
|
200
|
-
}
|
|
201
|
-
wrapWebGuest(handler, home = "/") {
|
|
202
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
203
|
-
return this.wrapWeb(async (request) => {
|
|
204
|
-
const user = await auth.resolve(request);
|
|
205
|
-
if (user) {
|
|
206
|
-
if (isEmailVerificationRequired() && !hasVerifiedEmail(user)) {
|
|
207
|
-
return Response.redirect("/email/verify", 302);
|
|
208
|
-
}
|
|
209
|
-
const location = typeof home === "function" ? await home(user) : home;
|
|
210
|
-
return Response.redirect(location, 302);
|
|
211
|
-
}
|
|
212
|
-
return handler(request);
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
wrapWebPublicRead(handler) {
|
|
216
|
-
if (isPublicReadsEnabled()) {
|
|
217
|
-
return this.wrapWeb(handler);
|
|
218
|
-
}
|
|
219
|
-
return this.wrapWebAuthenticated(handler);
|
|
220
|
-
}
|
|
221
|
-
wrapWebAuthenticated(handler) {
|
|
222
|
-
return this.wrapWebAuth(handler, { verified: true });
|
|
223
|
-
}
|
|
224
|
-
wrapWebAuthenticatedAllowUnverified(handler) {
|
|
225
|
-
return this.wrapWebAuth(handler, { verified: false });
|
|
226
|
-
}
|
|
227
|
-
wrapWebVerified(handler) {
|
|
228
|
-
return this.wrapWebAuth(handler, { verified: true });
|
|
229
|
-
}
|
|
230
|
-
wrapWebPasswordConfirm(handler) {
|
|
231
|
-
return this.wrapWebAuth(withMiddleware(createRequirePasswordConfirmMiddleware())(handler), {
|
|
232
|
-
verified: true
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
wrapWebAbility(ability, handler) {
|
|
236
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
237
|
-
const abilityChecker = resolveAbilityChecker(this.dependencies.container);
|
|
238
|
-
const requireAbility = createRequireAbilityMiddleware(abilityChecker);
|
|
239
|
-
const middleware = [
|
|
240
|
-
createRequireWebAuthMiddleware(auth),
|
|
241
|
-
...this.verifiedMiddleware(),
|
|
242
|
-
requireAbility(ability)
|
|
243
|
-
];
|
|
244
|
-
return this.wrapWeb(withMiddleware(...middleware)(handler));
|
|
245
|
-
}
|
|
246
|
-
wrapWebGlobalAdmin(handler) {
|
|
247
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
248
|
-
const middleware = [
|
|
249
|
-
createRequireWebAuthMiddleware(auth),
|
|
250
|
-
...this.verifiedMiddleware(),
|
|
251
|
-
createRequireGlobalAdminMiddleware()
|
|
252
|
-
];
|
|
253
|
-
return this.wrapWeb(withMiddleware(...middleware)(handler));
|
|
254
|
-
}
|
|
255
|
-
wrapAuthenticated(handler) {
|
|
256
|
-
return this.wrap("authenticated", handler);
|
|
257
|
-
}
|
|
258
|
-
wrapVerified(handler) {
|
|
259
|
-
const middleware = [...this.group("authenticated"), ...this.verifiedMiddleware()];
|
|
260
|
-
return withMiddleware(...middleware)(handler);
|
|
261
|
-
}
|
|
262
|
-
wrapPublicRead(handler) {
|
|
263
|
-
if (isPublicReadsEnabled()) {
|
|
264
|
-
return handler;
|
|
265
|
-
}
|
|
266
|
-
return this.wrapAuthenticated(handler);
|
|
267
|
-
}
|
|
268
|
-
wrapGlobalAdmin(handler) {
|
|
269
|
-
const middleware = [...this.group("authenticated"), createRequireGlobalAdminMiddleware()];
|
|
270
|
-
return withMiddleware(...middleware)(handler);
|
|
271
|
-
}
|
|
272
|
-
wrapAbility(ability, handler) {
|
|
273
|
-
const abilityChecker = resolveAbilityChecker(this.dependencies.container);
|
|
274
|
-
const requireAbility = createRequireAbilityMiddleware(abilityChecker);
|
|
275
|
-
const middleware = [...this.group("authenticated"), requireAbility(ability)];
|
|
276
|
-
return withMiddleware(...middleware)(handler);
|
|
277
|
-
}
|
|
278
|
-
wrapPolicy(resource, action, handler) {
|
|
279
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
280
|
-
const gate = this.dependencies.container.resolve(CORE_POLICY_GATE_TOKEN);
|
|
281
|
-
return withMiddleware(createAuthorizeMiddleware(gate, auth, resource, action))(handler);
|
|
282
|
-
}
|
|
283
|
-
wrapLogin(handler) {
|
|
284
|
-
return this.wrapThrottle("login", resolveLoginRateLimit(), handler);
|
|
285
|
-
}
|
|
286
|
-
wrapSigned(handler) {
|
|
287
|
-
return withMiddleware(createValidateSignatureMiddleware())(handler);
|
|
288
|
-
}
|
|
289
|
-
wrapRegister(handler) {
|
|
290
|
-
return this.wrapThrottle("register", resolveRegisterRateLimit(), handler);
|
|
291
|
-
}
|
|
292
|
-
wrapWebAuth(handler, options) {
|
|
293
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
294
|
-
const middleware = [
|
|
295
|
-
createRequireWebAuthMiddleware(auth),
|
|
296
|
-
...options.verified ? this.verifiedMiddleware() : []
|
|
297
|
-
];
|
|
298
|
-
return this.wrapWeb(withMiddleware(...middleware)(handler));
|
|
299
|
-
}
|
|
300
|
-
verifiedMiddleware() {
|
|
301
|
-
const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
|
|
302
|
-
return [createRequireVerifiedMiddleware(auth)];
|
|
303
|
-
}
|
|
304
|
-
wrapThrottle(scope, rateLimit, handler) {
|
|
305
|
-
const middleware = [];
|
|
306
|
-
const memoryKeyPrefix = scope === "login" ? "login-throttle:" : "register-throttle:";
|
|
307
|
-
if (this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
|
|
308
|
-
const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
|
|
309
|
-
const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
|
|
310
|
-
if (redisUrl) {
|
|
311
|
-
const throttle = scope === "login" ? createLoginThrottleMiddleware({
|
|
312
|
-
redisUrl,
|
|
313
|
-
maxAttempts: rateLimit.maxAttempts,
|
|
314
|
-
decaySeconds: rateLimit.decaySeconds
|
|
315
|
-
}) : createThrottleMiddleware({
|
|
316
|
-
redisUrl,
|
|
317
|
-
maxAttempts: rateLimit.maxAttempts,
|
|
318
|
-
decaySeconds: rateLimit.decaySeconds,
|
|
319
|
-
keyPrefix: memoryKeyPrefix
|
|
320
|
-
});
|
|
321
|
-
middleware.push(throttle);
|
|
322
|
-
} else {
|
|
323
|
-
middleware.push(createMemoryThrottleMiddleware({
|
|
324
|
-
maxAttempts: rateLimit.maxAttempts,
|
|
325
|
-
decaySeconds: rateLimit.decaySeconds,
|
|
326
|
-
keyPrefix: memoryKeyPrefix
|
|
327
|
-
}));
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
middleware.push(createMemoryThrottleMiddleware({
|
|
331
|
-
maxAttempts: rateLimit.maxAttempts,
|
|
332
|
-
decaySeconds: rateLimit.decaySeconds,
|
|
333
|
-
keyPrefix: memoryKeyPrefix
|
|
334
|
-
}));
|
|
335
|
-
}
|
|
336
|
-
if (middleware.length === 0) {
|
|
337
|
-
return handler;
|
|
338
|
-
}
|
|
339
|
-
return withMiddleware(...middleware)(handler);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
function createHttpKernel(dependencies) {
|
|
343
|
-
return new HttpKernel(dependencies);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// ../../src/bootstrap/discoverModules.ts
|
|
347
|
-
import { readdirSync } from "fs";
|
|
348
|
-
import { join } from "path";
|
|
349
|
-
import { pathToFileURL } from "url";
|
|
350
|
-
var DISCOVER_MODULES_STATE_KEY = Symbol.for("@getstrata/discoverModulesState");
|
|
351
|
-
function readDiscoverModulesState() {
|
|
352
|
-
const existing = globalThis[DISCOVER_MODULES_STATE_KEY];
|
|
353
|
-
if (existing) {
|
|
354
|
-
return existing;
|
|
355
|
-
}
|
|
356
|
-
const state = { appModules: [] };
|
|
357
|
-
globalThis[DISCOVER_MODULES_STATE_KEY] = state;
|
|
358
|
-
return state;
|
|
359
|
-
}
|
|
360
|
-
function configureModulesDirectory(modulesDir) {
|
|
361
|
-
const state = readDiscoverModulesState();
|
|
362
|
-
if (state.configuredModulesDir !== modulesDir) {
|
|
363
|
-
state.appModules.length = 0;
|
|
364
|
-
state.modulesReady = undefined;
|
|
365
|
-
}
|
|
366
|
-
state.configuredModulesDir = modulesDir;
|
|
367
|
-
}
|
|
368
|
-
function resolveModulesDirectory(options) {
|
|
369
|
-
const state = readDiscoverModulesState();
|
|
370
|
-
if (options?.modulesDir) {
|
|
371
|
-
return options.modulesDir;
|
|
372
|
-
}
|
|
373
|
-
if (state.configuredModulesDir) {
|
|
374
|
-
return state.configuredModulesDir;
|
|
375
|
-
}
|
|
376
|
-
throw new Error("configureModulesDirectory() must be called before discovering modules. The app preload (or starter) should call it.");
|
|
377
|
-
}
|
|
378
|
-
async function loadDiscoveredModules(options) {
|
|
379
|
-
const modulesDirectory = resolveModulesDirectory(options);
|
|
380
|
-
let moduleNames;
|
|
381
|
-
try {
|
|
382
|
-
moduleNames = readdirSync(modulesDirectory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
383
|
-
} catch (error) {
|
|
384
|
-
if (error.code === "ENOENT") {
|
|
385
|
-
return [];
|
|
386
|
-
}
|
|
387
|
-
throw error;
|
|
388
|
-
}
|
|
389
|
-
const modules = await Promise.all(moduleNames.map(async (moduleName) => {
|
|
390
|
-
const moduleUrl = pathToFileURL(join(modulesDirectory, moduleName, "index.ts")).href;
|
|
391
|
-
const loaded = await import(moduleUrl);
|
|
392
|
-
return loaded.default;
|
|
393
|
-
}));
|
|
394
|
-
return modules.filter((module) => module?.name !== undefined).sort((left, right) => (left.order ?? 100) - (right.order ?? 100));
|
|
395
|
-
}
|
|
396
|
-
async function ensureModulesLoaded(options) {
|
|
397
|
-
const state = readDiscoverModulesState();
|
|
398
|
-
if (state.appModules.length > 0) {
|
|
399
|
-
return state.appModules;
|
|
400
|
-
}
|
|
401
|
-
state.modulesReady ??= loadDiscoveredModules(options).then((modules) => {
|
|
402
|
-
state.appModules.splice(0, state.appModules.length, ...modules);
|
|
403
|
-
return state.appModules;
|
|
404
|
-
});
|
|
405
|
-
return state.modulesReady;
|
|
406
|
-
}
|
|
407
|
-
function discoverModules() {
|
|
408
|
-
return readDiscoverModulesState().appModules;
|
|
409
|
-
}
|
|
410
|
-
function resetDiscoverModulesForTests() {
|
|
411
|
-
const state = readDiscoverModulesState();
|
|
412
|
-
state.configuredModulesDir = undefined;
|
|
413
|
-
state.appModules.length = 0;
|
|
414
|
-
state.modulesReady = undefined;
|
|
415
|
-
}
|
|
416
|
-
// ../../src/bootstrap/prefixRouteMap.ts
|
|
417
|
-
function prefixRouteMap(prefix, routes) {
|
|
418
|
-
const normalizedPrefix = prefix.replace(/\/$/, "");
|
|
419
|
-
const prefixed = {};
|
|
420
|
-
for (const [path, handler] of Object.entries(routes)) {
|
|
421
|
-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
422
|
-
prefixed[`${normalizedPrefix}${normalizedPath}`] = handler;
|
|
423
|
-
}
|
|
424
|
-
return prefixed;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// ../../src/bootstrap/routeRegistry.ts
|
|
428
|
-
class RouteRegistry {
|
|
429
|
-
routes = [];
|
|
430
|
-
register(route) {
|
|
431
|
-
this.routes.push(route);
|
|
432
|
-
}
|
|
433
|
-
clear() {
|
|
434
|
-
this.routes.length = 0;
|
|
435
|
-
}
|
|
436
|
-
list() {
|
|
437
|
-
return [...this.routes].sort((left, right) => left.path.localeCompare(right.path));
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
var ROUTE_REGISTRY_KEY = Symbol.for("@getstrata/routeRegistry");
|
|
441
|
-
function readSharedRouteRegistry() {
|
|
442
|
-
const globalRegistry = globalThis[ROUTE_REGISTRY_KEY];
|
|
443
|
-
if (globalRegistry) {
|
|
444
|
-
return globalRegistry;
|
|
445
|
-
}
|
|
446
|
-
const registry = new RouteRegistry;
|
|
447
|
-
globalThis[ROUTE_REGISTRY_KEY] = registry;
|
|
448
|
-
return registry;
|
|
449
|
-
}
|
|
450
|
-
var routeRegistry = readSharedRouteRegistry();
|
|
451
|
-
|
|
452
|
-
// ../../src/bootstrap/buildModuleRoutes.ts
|
|
453
|
-
function registerOpenApiRoute(method, path, middleware) {
|
|
454
|
-
routeRegistry.register({ method, path, middleware });
|
|
455
|
-
}
|
|
456
|
-
function registerOpenApiRouteMap(routes, middleware) {
|
|
457
|
-
const registered = {};
|
|
458
|
-
for (const [path, handler] of Object.entries(routes)) {
|
|
459
|
-
if (handler && typeof handler === "object" && !Array.isArray(handler)) {
|
|
460
|
-
const methodMap = handler;
|
|
461
|
-
registered[path] = methodMap;
|
|
462
|
-
for (const method of Object.keys(methodMap)) {
|
|
463
|
-
registerOpenApiRoute(method.toUpperCase(), path, middleware);
|
|
464
|
-
}
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
registered[path] = handler;
|
|
468
|
-
registerOpenApiRoute("GET", path, middleware);
|
|
469
|
-
}
|
|
470
|
-
return registered;
|
|
471
|
-
}
|
|
472
|
-
function createCachedJson(dependencies) {
|
|
473
|
-
return async (cacheKey, loader, tags = [], request) => {
|
|
474
|
-
const data = tags.length > 0 ? await dependencies.cache.tags(...tags).remember(cacheKey, loader) : await dependencies.cache.remember(cacheKey, loader);
|
|
475
|
-
return conditionalJsonResponse(request, data);
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
function buildModuleRoutes(dependencies, options = {}) {
|
|
479
|
-
const { apiPrefix = "", modules = discoverModules(), clearRegistry = true } = options;
|
|
480
|
-
if (clearRegistry) {
|
|
481
|
-
routeRegistry.clear();
|
|
482
|
-
}
|
|
483
|
-
const kernel = createHttpKernel(dependencies);
|
|
484
|
-
const middleware = [...kernel.globalMiddleware(), ...kernel.group("api")];
|
|
485
|
-
const cachedJson = createCachedJson(dependencies);
|
|
486
|
-
const moduleRoutes = {};
|
|
487
|
-
for (const module of modules) {
|
|
488
|
-
if (!module.routes) {
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
Object.assign(moduleRoutes, module.routes({ dependencies, cachedJson, kernel }));
|
|
492
|
-
}
|
|
493
|
-
const prefixedModuleRoutes = prefixRouteMap(apiPrefix, moduleRoutes);
|
|
494
|
-
return applyMiddlewareToRoutes(registerOpenApiRouteMap(prefixedModuleRoutes, ["global", "api"]), middleware);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// ../../src/bootstrap/createSpaRoutes.ts
|
|
498
|
-
import { join as join2 } from "path";
|
|
499
|
-
import { jsonResponse } from "@getstrata/core/http/response";
|
|
500
|
-
import { isSpaEnabled, isViewsEnabled as isViewsEnabled2, readSpaPrefix } from "@getstrata/core/runtime/frontendMode";
|
|
501
|
-
var SPA_DIST_DIRECTORY = join2(process.cwd(), "frontend/dist");
|
|
502
|
-
function relativeSpaPath(pathname, prefix) {
|
|
503
|
-
if (pathname === prefix || pathname === `${prefix}/`) {
|
|
504
|
-
return "";
|
|
505
|
-
}
|
|
506
|
-
if (pathname.startsWith(`${prefix}/`)) {
|
|
507
|
-
return pathname.slice(prefix.length + 1);
|
|
508
|
-
}
|
|
509
|
-
return "";
|
|
510
|
-
}
|
|
511
|
-
function createSpaDocumentHandler(prefix, distDirectory) {
|
|
512
|
-
const indexFilePath = join2(distDirectory, "index.html");
|
|
513
|
-
return async (request) => {
|
|
514
|
-
const pathname = new URL(request.url).pathname;
|
|
515
|
-
if (pathname.startsWith("/api/")) {
|
|
516
|
-
return new Response("Not found", { status: 404 });
|
|
517
|
-
}
|
|
518
|
-
const relativePath = relativeSpaPath(pathname, prefix);
|
|
519
|
-
const assetFile = Bun.file(join2(distDirectory, relativePath));
|
|
520
|
-
if (relativePath.length > 0 && await assetFile.exists()) {
|
|
521
|
-
return new Response(assetFile);
|
|
522
|
-
}
|
|
523
|
-
const indexFile = Bun.file(indexFilePath);
|
|
524
|
-
if (await indexFile.exists()) {
|
|
525
|
-
return new Response(indexFile, {
|
|
526
|
-
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
return jsonResponse({
|
|
530
|
-
error: "SPA build not found. Run `bun run frontend:build` in your app."
|
|
531
|
-
}, { status: 503 });
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
function createSpaRoutes(_dependencies, options = {}) {
|
|
535
|
-
const prefix = options.prefix ?? readSpaPrefix();
|
|
536
|
-
const distDirectory = options.distDirectory ?? SPA_DIST_DIRECTORY;
|
|
537
|
-
const wrap = options.wrap ?? ((handler) => handler);
|
|
538
|
-
const handler = wrap(createSpaDocumentHandler(prefix, distDirectory));
|
|
539
|
-
const routes = {
|
|
540
|
-
[prefix]: handler,
|
|
541
|
-
[`${prefix}/`]: handler,
|
|
542
|
-
[`${prefix}/*`]: handler
|
|
543
|
-
};
|
|
544
|
-
if (!isViewsEnabled2()) {
|
|
545
|
-
routes["/"] = async () => Response.redirect(`${prefix}/`, 302);
|
|
546
|
-
}
|
|
547
|
-
return routes;
|
|
548
|
-
}
|
|
549
|
-
function mergeSpaRoutes(dependencies, routes, options) {
|
|
550
|
-
if (!isSpaEnabled()) {
|
|
551
|
-
return routes;
|
|
552
|
-
}
|
|
553
|
-
return {
|
|
554
|
-
...createSpaRoutes(dependencies, options),
|
|
555
|
-
...routes
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// ../../src/bootstrap/createWebRoutes.ts
|
|
560
|
-
import { join as join3 } from "path";
|
|
561
|
-
import { isViewsEnabled as isViewsEnabled3 } from "@getstrata/core/runtime/frontendMode";
|
|
562
|
-
import { notFoundHtmlResponse } from "@getstrata/core/view";
|
|
563
|
-
|
|
564
|
-
// ../../src/bootstrap/buildWebModuleRoutes.ts
|
|
565
|
-
import { applyMiddlewareToRoutes as applyMiddlewareToRoutes2 } from "@getstrata/core/http/middleware";
|
|
566
|
-
function buildWebModuleRoutes(dependencies, options = {}) {
|
|
567
|
-
const { modules = discoverModules(), clearRegistry = true, seedRoutes = {} } = options;
|
|
568
|
-
if (clearRegistry) {
|
|
569
|
-
routeRegistry.clear();
|
|
570
|
-
}
|
|
571
|
-
const kernel = createHttpKernel(dependencies);
|
|
572
|
-
const middleware = kernel.globalMiddleware();
|
|
573
|
-
const moduleRoutes = { ...seedRoutes };
|
|
574
|
-
for (const module of modules) {
|
|
575
|
-
if (!module.webRoutes) {
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
Object.assign(moduleRoutes, module.webRoutes({
|
|
579
|
-
dependencies,
|
|
580
|
-
cachedJson: async () => new Response(""),
|
|
581
|
-
kernel
|
|
582
|
-
}));
|
|
583
|
-
}
|
|
584
|
-
return applyMiddlewareToRoutes2(registerOpenApiRouteMap(moduleRoutes, ["global", "web"]), middleware);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// ../../src/bootstrap/createWebRoutes.ts
|
|
588
|
-
function registerRoute(method, path, middleware) {
|
|
589
|
-
routeRegistry.register({ method, path, middleware });
|
|
590
|
-
}
|
|
591
|
-
function createWebRoutes(dependencies, options = {}) {
|
|
592
|
-
const wrappedRoutes = buildWebModuleRoutes(dependencies, {
|
|
593
|
-
clearRegistry: false,
|
|
594
|
-
modules: options.modules
|
|
595
|
-
});
|
|
596
|
-
registerRoute("GET", "/", ["global", "web"]);
|
|
597
|
-
wrappedRoutes["/assets/*"] = async (request) => {
|
|
598
|
-
registerRoute("GET", "/assets/*", ["global", "web"]);
|
|
599
|
-
const pathname = new URL(request.url).pathname;
|
|
600
|
-
const relativePath = pathname.replace(/^\//, "");
|
|
601
|
-
const file = Bun.file(join3(process.cwd(), "public", relativePath));
|
|
602
|
-
if (!await file.exists()) {
|
|
603
|
-
return notFoundHtmlResponse();
|
|
604
|
-
}
|
|
605
|
-
return new Response(file);
|
|
606
|
-
};
|
|
607
|
-
registerRoute("GET", "/assets/*", ["global", "web"]);
|
|
608
|
-
return wrappedRoutes;
|
|
609
|
-
}
|
|
610
|
-
function mergeWebRoutes(dependencies, routes, options = {}) {
|
|
611
|
-
if (!isViewsEnabled3()) {
|
|
612
|
-
return routes;
|
|
613
|
-
}
|
|
614
|
-
return {
|
|
615
|
-
...createWebRoutes(dependencies, options),
|
|
616
|
-
...routes
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// ../../src/bootstrap/dogfoodApp.ts
|
|
621
|
-
function isHiroappDogfood() {
|
|
622
|
-
return true;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// ../../src/bootstrap/health.ts
|
|
626
|
-
import { getBoundDatabaseConnection } from "@getstrata/core/database/boundConnection";
|
|
627
|
-
import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
|
|
628
|
-
import { jsonResponse as jsonResponse2 } from "@getstrata/core/http/response";
|
|
629
|
-
var {RedisClient } = globalThis.Bun;
|
|
630
|
-
function resolveRedisUrl(dependencies) {
|
|
631
|
-
if (!dependencies.container.has(CORE_CONFIG_TOKEN)) {
|
|
632
|
-
return process.env.REDIS_URL?.trim() || undefined;
|
|
633
|
-
}
|
|
634
|
-
const config = dependencies.container.resolve(CORE_CONFIG_TOKEN);
|
|
635
|
-
const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim();
|
|
636
|
-
return redisUrl || undefined;
|
|
637
|
-
}
|
|
638
|
-
function resolveHealthDatabase() {
|
|
639
|
-
const bound = getBoundDatabaseConnection();
|
|
640
|
-
if (bound) {
|
|
641
|
-
return bound;
|
|
642
|
-
}
|
|
643
|
-
try {
|
|
644
|
-
return getDefaultDatabasePool();
|
|
645
|
-
} catch {
|
|
646
|
-
return null;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
async function pingDatabaseClient(connection) {
|
|
650
|
-
try {
|
|
651
|
-
await connection.unsafe("SELECT 1");
|
|
652
|
-
return true;
|
|
653
|
-
} catch {
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
async function checkDatabase() {
|
|
658
|
-
const connection = resolveHealthDatabase();
|
|
659
|
-
if (!connection) {
|
|
660
|
-
return false;
|
|
661
|
-
}
|
|
662
|
-
return await pingDatabaseClient(connection);
|
|
663
|
-
}
|
|
664
|
-
async function pingDatabase() {
|
|
665
|
-
return await checkDatabase();
|
|
666
|
-
}
|
|
667
|
-
async function checkRedis(redisUrl) {
|
|
668
|
-
try {
|
|
669
|
-
const client = new RedisClient(redisUrl);
|
|
670
|
-
const response = await client.ping();
|
|
671
|
-
return response === "PONG";
|
|
672
|
-
} catch {
|
|
673
|
-
return false;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
async function resolveExtraFields(extra) {
|
|
677
|
-
if (!extra) {
|
|
678
|
-
return {};
|
|
679
|
-
}
|
|
680
|
-
return typeof extra === "function" ? await extra() : extra;
|
|
681
|
-
}
|
|
682
|
-
async function collectDependencyChecks(dependencies) {
|
|
683
|
-
const checks = {
|
|
684
|
-
database: await checkDatabase() ? "ok" : "error"
|
|
685
|
-
};
|
|
686
|
-
const redisUrl = resolveRedisUrl(dependencies);
|
|
687
|
-
if (redisUrl) {
|
|
688
|
-
checks.redis = await checkRedis(redisUrl) ? "ok" : "error";
|
|
689
|
-
} else {
|
|
690
|
-
checks.redis = "skipped";
|
|
691
|
-
}
|
|
692
|
-
const ready = checks.database === "ok" && (checks.redis === "ok" || checks.redis === "skipped");
|
|
693
|
-
return { checks, ready };
|
|
694
|
-
}
|
|
695
|
-
function createHealthRoutes(dependencies, options = {}) {
|
|
696
|
-
return {
|
|
697
|
-
"/health": async () => {
|
|
698
|
-
const extra = await resolveExtraFields(options.extra);
|
|
699
|
-
if (!options.pingOnHealth) {
|
|
700
|
-
return jsonResponse2({ status: "ok", ...extra });
|
|
701
|
-
}
|
|
702
|
-
const { checks, ready } = await collectDependencyChecks(dependencies);
|
|
703
|
-
return jsonResponse2({
|
|
704
|
-
status: ready ? "ok" : "error",
|
|
705
|
-
checks,
|
|
706
|
-
...extra
|
|
707
|
-
}, { status: ready ? 200 : 503 });
|
|
708
|
-
},
|
|
709
|
-
"/ready": async () => {
|
|
710
|
-
const extra = await resolveExtraFields(options.extra);
|
|
711
|
-
const { checks, ready } = await collectDependencyChecks(dependencies);
|
|
712
|
-
return jsonResponse2({
|
|
713
|
-
status: ready ? "ready" : "not_ready",
|
|
714
|
-
checks,
|
|
715
|
-
...extra
|
|
716
|
-
}, { status: ready ? 200 : 503 });
|
|
717
|
-
}
|
|
718
|
-
};
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// ../../src/bootstrap/metricsRoutes.ts
|
|
722
|
-
import { timingSafeEqual } from "crypto";
|
|
723
|
-
import { prometheusRegistry } from "@getstrata/core/metrics/prometheus";
|
|
724
|
-
function tokensMatch(left, right) {
|
|
725
|
-
const leftBuffer = Buffer.from(left);
|
|
726
|
-
const rightBuffer = Buffer.from(right);
|
|
727
|
-
if (leftBuffer.length !== rightBuffer.length) {
|
|
728
|
-
return false;
|
|
729
|
-
}
|
|
730
|
-
return timingSafeEqual(leftBuffer, rightBuffer);
|
|
731
|
-
}
|
|
732
|
-
function authorizeMetrics(request) {
|
|
733
|
-
const expected = process.env.METRICS_TOKEN?.trim();
|
|
734
|
-
const authorization = request.headers.get("authorization") ?? "";
|
|
735
|
-
const presented = authorization.startsWith("Bearer ") ? authorization.slice("Bearer ".length) : "";
|
|
736
|
-
if (expected) {
|
|
737
|
-
return presented.length > 0 && tokensMatch(presented, expected);
|
|
738
|
-
}
|
|
739
|
-
if ((process.env.APP_ENV ?? "local") === "production") {
|
|
740
|
-
return false;
|
|
741
|
-
}
|
|
742
|
-
return true;
|
|
743
|
-
}
|
|
744
|
-
function createMetricsRoutes() {
|
|
745
|
-
return {
|
|
746
|
-
"/metrics": async (request) => {
|
|
747
|
-
if (!authorizeMetrics(request)) {
|
|
748
|
-
return new Response("Not Found", { status: 404 });
|
|
749
|
-
}
|
|
750
|
-
return new Response(prometheusRegistry.renderMetrics(), {
|
|
751
|
-
status: 200,
|
|
752
|
-
headers: {
|
|
753
|
-
"content-type": "text/plain; version=0.0.4; charset=utf-8"
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// ../../src/bootstrap/createRoutes.ts
|
|
761
|
-
function registerRoute2(method, path, middleware) {
|
|
762
|
-
routeRegistry.register({ method, path, middleware });
|
|
763
|
-
}
|
|
764
|
-
function createRoutes(dependencies) {
|
|
765
|
-
const apiPrefix = isHiroappDogfood() ? "" : appConfig.apiPrefix;
|
|
766
|
-
const wrappedModuleRoutes = buildModuleRoutes(dependencies, {
|
|
767
|
-
apiPrefix,
|
|
768
|
-
clearRegistry: true,
|
|
769
|
-
modules: []
|
|
770
|
-
});
|
|
771
|
-
const healthRoutes = createHealthRoutes(dependencies);
|
|
772
|
-
const metricsRoutes = createMetricsRoutes();
|
|
773
|
-
registerRoute2("GET", "/health", []);
|
|
774
|
-
registerRoute2("GET", "/ready", []);
|
|
775
|
-
registerRoute2("GET", "/metrics", []);
|
|
776
|
-
const notFoundApiPath = `${apiPrefix || "/api"}/*`;
|
|
777
|
-
const baseRoutes = {
|
|
778
|
-
...healthRoutes,
|
|
779
|
-
...metricsRoutes,
|
|
780
|
-
...isViewsEnabled4() || isSpaEnabled2() ? {} : { "/": strata_default },
|
|
781
|
-
...wrappedModuleRoutes,
|
|
782
|
-
[notFoundApiPath]: async () => {
|
|
783
|
-
registerRoute2("GET", notFoundApiPath, ["global", "api"]);
|
|
784
|
-
return jsonResponse3({ error: "Not Found" }, { status: 404 });
|
|
785
|
-
},
|
|
786
|
-
"/*": async () => {
|
|
787
|
-
registerRoute2("GET", "/*", []);
|
|
788
|
-
if (isViewsEnabled4()) {
|
|
789
|
-
return notFoundHtmlResponse2();
|
|
790
|
-
}
|
|
791
|
-
if (isSpaEnabled2()) {
|
|
792
|
-
return jsonResponse3({ error: "Not Found" }, { status: 404 });
|
|
793
|
-
}
|
|
794
|
-
return jsonResponse3({ error: "Not Found" }, { status: 404 });
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
return mergeSpaRoutes(dependencies, mergeWebRoutes(dependencies, baseRoutes));
|
|
798
|
-
}
|
|
799
|
-
export {
|
|
800
|
-
createRoutes
|
|
801
|
-
};
|