@stacksjs/server 0.70.87 → 0.70.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config-production.d.ts +22 -0
- package/dist/config-production.js +16 -0
- package/dist/config.js +60 -0
- package/dist/controllers/base.js +38 -0
- package/dist/imports.js +224 -0
- package/dist/index.js +5 -1309
- package/dist/maintenance.js +365 -0
- package/dist/proxy.js +28 -0
- package/dist/start.d.ts +1 -0
- package/dist/start.js +54 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,1309 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Controller {
|
|
8
|
-
json(data, status = 200) {
|
|
9
|
-
return response.json(data, status);
|
|
10
|
-
}
|
|
11
|
-
success(data) {
|
|
12
|
-
return this.json(data, 200);
|
|
13
|
-
}
|
|
14
|
-
created(data) {
|
|
15
|
-
return this.json(data, 201);
|
|
16
|
-
}
|
|
17
|
-
noContent() {
|
|
18
|
-
return response.noContent();
|
|
19
|
-
}
|
|
20
|
-
error(message, status = 500) {
|
|
21
|
-
return this.json({ error: message }, status);
|
|
22
|
-
}
|
|
23
|
-
notFound(message = "Resource not found") {
|
|
24
|
-
return this.error(message, 404);
|
|
25
|
-
}
|
|
26
|
-
unauthorized(message = "Unauthorized") {
|
|
27
|
-
return this.error(message, 401);
|
|
28
|
-
}
|
|
29
|
-
forbidden(message = "Forbidden") {
|
|
30
|
-
return this.error(message, 403);
|
|
31
|
-
}
|
|
32
|
-
validate(request, rules) {
|
|
33
|
-
try {
|
|
34
|
-
const result = request.validate(rules);
|
|
35
|
-
log.info("Validation result:", result);
|
|
36
|
-
return Promise.resolve();
|
|
37
|
-
} catch (error) {
|
|
38
|
-
return Promise.reject(error);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// src/imports.ts
|
|
43
|
-
import { existsSync } from "fs";
|
|
44
|
-
import { dirname, relative } from "path";
|
|
45
|
-
var {plugin } = globalThis.Bun;
|
|
46
|
-
import { log as log2 } from "@stacksjs/logging";
|
|
47
|
-
import { path as path2 } from "@stacksjs/path";
|
|
48
|
-
|
|
49
|
-
// ../../../../pantry/bun-plugin-auto-imports/dist/index.js
|
|
50
|
-
import path from "path";
|
|
51
|
-
function generateESLintGlobals(dtsContent, options = {}) {
|
|
52
|
-
if (typeof dtsContent !== "string") {
|
|
53
|
-
throw new TypeError("dtsContent must be a string");
|
|
54
|
-
}
|
|
55
|
-
if (!dtsContent.trim()) {
|
|
56
|
-
throw new Error("dtsContent cannot be empty");
|
|
57
|
-
}
|
|
58
|
-
const {
|
|
59
|
-
globalsPropValue = true
|
|
60
|
-
} = options;
|
|
61
|
-
const globals = {};
|
|
62
|
-
try {
|
|
63
|
-
const globalBlockMatch = dtsContent.match(/declare\s+global\s*\{([^}]*)\}/);
|
|
64
|
-
if (!globalBlockMatch || !globalBlockMatch[1]) {
|
|
65
|
-
console.warn("No global declarations found in dts content");
|
|
66
|
-
return JSON.stringify({ globals: {} }, null, 2);
|
|
67
|
-
}
|
|
68
|
-
const globalBlock = globalBlockMatch[1];
|
|
69
|
-
const constDeclarations = globalBlock.match(/const\s+(\w+):/g);
|
|
70
|
-
if (constDeclarations) {
|
|
71
|
-
constDeclarations.forEach((declaration) => {
|
|
72
|
-
const name = declaration.replace(/const\s+|:/g, "").trim();
|
|
73
|
-
if (name)
|
|
74
|
-
globals[name] = globalsPropValue;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
const typeDeclarations = globalBlock.match(/type\s+(\w+)\s*=/g);
|
|
78
|
-
if (typeDeclarations) {
|
|
79
|
-
typeDeclarations.forEach((declaration) => {
|
|
80
|
-
const name = declaration.replace(/type\s+|=/g, "").trim();
|
|
81
|
-
if (name)
|
|
82
|
-
globals[name] = globalsPropValue;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
const output = {
|
|
86
|
-
globals
|
|
87
|
-
};
|
|
88
|
-
return JSON.stringify(output, null, 2);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error("Error generating ESLint globals:", error instanceof Error ? error.message : error);
|
|
91
|
-
throw new Error("Failed to generate ESLint globals configuration");
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
var { Glob } = globalThis.Bun;
|
|
95
|
-
function getLoader(filePath) {
|
|
96
|
-
if (filePath.endsWith(".ts"))
|
|
97
|
-
return "ts";
|
|
98
|
-
if (filePath.endsWith(".js"))
|
|
99
|
-
return "js";
|
|
100
|
-
if (filePath.endsWith(".tsx"))
|
|
101
|
-
return "tsx";
|
|
102
|
-
return "jsx";
|
|
103
|
-
}
|
|
104
|
-
var GENERATED_COMMENT = `// Generated by bun-plugin-auto-imports
|
|
105
|
-
`;
|
|
106
|
-
function stripLiterals(code) {
|
|
107
|
-
const parts = [];
|
|
108
|
-
let i = 0;
|
|
109
|
-
let lastKeepEnd = 0;
|
|
110
|
-
const len = code.length;
|
|
111
|
-
while (i < len) {
|
|
112
|
-
if (code[i] === "/" && i + 1 < len && code[i + 1] === "/") {
|
|
113
|
-
parts.push(code.slice(lastKeepEnd, i));
|
|
114
|
-
while (i < len && code[i] !== `
|
|
115
|
-
`)
|
|
116
|
-
i++;
|
|
117
|
-
lastKeepEnd = i;
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
if (code[i] === "/" && i + 1 < len && code[i + 1] === "*") {
|
|
121
|
-
parts.push(code.slice(lastKeepEnd, i));
|
|
122
|
-
i += 2;
|
|
123
|
-
while (i < len && !(code[i] === "*" && i + 1 < len && code[i + 1] === "/"))
|
|
124
|
-
i++;
|
|
125
|
-
if (i < len)
|
|
126
|
-
i += 2;
|
|
127
|
-
lastKeepEnd = i;
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (code[i] === "`") {
|
|
131
|
-
parts.push(code.slice(lastKeepEnd, i));
|
|
132
|
-
i++;
|
|
133
|
-
while (i < len && code[i] !== "`") {
|
|
134
|
-
if (code[i] === "\\") {
|
|
135
|
-
i += 2;
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (code[i] === "$" && i + 1 < len && code[i + 1] === "{") {
|
|
139
|
-
i += 2;
|
|
140
|
-
const exprStart = i;
|
|
141
|
-
let depth = 1;
|
|
142
|
-
while (i < len && depth > 0) {
|
|
143
|
-
if (code[i] === "\\") {
|
|
144
|
-
i += 2;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (code[i] === '"' || code[i] === "'") {
|
|
148
|
-
const q = code[i];
|
|
149
|
-
i++;
|
|
150
|
-
while (i < len && code[i] !== q) {
|
|
151
|
-
if (code[i] === "\\")
|
|
152
|
-
i++;
|
|
153
|
-
i++;
|
|
154
|
-
}
|
|
155
|
-
if (i < len)
|
|
156
|
-
i++;
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
if (code[i] === "`") {
|
|
160
|
-
i++;
|
|
161
|
-
while (i < len && code[i] !== "`") {
|
|
162
|
-
if (code[i] === "\\") {
|
|
163
|
-
i += 2;
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (code[i] === "$" && i + 1 < len && code[i + 1] === "{") {
|
|
167
|
-
i += 2;
|
|
168
|
-
let nd = 1;
|
|
169
|
-
while (i < len && nd > 0) {
|
|
170
|
-
if (code[i] === "{")
|
|
171
|
-
nd++;
|
|
172
|
-
else if (code[i] === "}")
|
|
173
|
-
nd--;
|
|
174
|
-
if (nd > 0)
|
|
175
|
-
i++;
|
|
176
|
-
}
|
|
177
|
-
if (i < len)
|
|
178
|
-
i++;
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
i++;
|
|
182
|
-
}
|
|
183
|
-
if (i < len)
|
|
184
|
-
i++;
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
if (code[i] === "{")
|
|
188
|
-
depth++;
|
|
189
|
-
else if (code[i] === "}")
|
|
190
|
-
depth--;
|
|
191
|
-
if (depth > 0)
|
|
192
|
-
i++;
|
|
193
|
-
}
|
|
194
|
-
parts.push(` ${code.slice(exprStart, i)} `);
|
|
195
|
-
if (i < len)
|
|
196
|
-
i++;
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
i++;
|
|
200
|
-
}
|
|
201
|
-
if (i < len)
|
|
202
|
-
i++;
|
|
203
|
-
lastKeepEnd = i;
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
if (code[i] === '"' || code[i] === "'") {
|
|
207
|
-
parts.push(code.slice(lastKeepEnd, i));
|
|
208
|
-
const quote = code[i];
|
|
209
|
-
i++;
|
|
210
|
-
while (i < len && code[i] !== quote) {
|
|
211
|
-
if (code[i] === "\\")
|
|
212
|
-
i++;
|
|
213
|
-
i++;
|
|
214
|
-
}
|
|
215
|
-
if (i < len)
|
|
216
|
-
i++;
|
|
217
|
-
lastKeepEnd = i;
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
i++;
|
|
221
|
-
}
|
|
222
|
-
if (lastKeepEnd < len) {
|
|
223
|
-
parts.push(code.slice(lastKeepEnd));
|
|
224
|
-
}
|
|
225
|
-
return parts.join(" ");
|
|
226
|
-
}
|
|
227
|
-
function detectUsedIdentifiers(strippedCode, knownNames) {
|
|
228
|
-
const used = new Set;
|
|
229
|
-
if (knownNames.size === 0)
|
|
230
|
-
return used;
|
|
231
|
-
const regex = /(?<![.\w$])([a-zA-Z_$][\w$]*)/g;
|
|
232
|
-
let match;
|
|
233
|
-
while ((match = regex.exec(strippedCode)) !== null) {
|
|
234
|
-
if (match[1] && knownNames.has(match[1])) {
|
|
235
|
-
used.add(match[1]);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return used;
|
|
239
|
-
}
|
|
240
|
-
function removeAlreadyImported(code, usedNames) {
|
|
241
|
-
const importRegex = /(?:import|export)\s+(?:type\s+)?(?:\{([^}]*)\}|(\*\s+as\s+\w+)|(\w+))(?:\s*,\s*(?:\{([^}]*)\}|(\*\s+as\s+\w+)))?\s+from\s+/g;
|
|
242
|
-
let match;
|
|
243
|
-
while ((match = importRegex.exec(code)) !== null) {
|
|
244
|
-
const namedGroups = [match[1], match[4]];
|
|
245
|
-
for (const group of namedGroups) {
|
|
246
|
-
if (group) {
|
|
247
|
-
for (const part of group.split(",")) {
|
|
248
|
-
const trimmed = part.trim();
|
|
249
|
-
if (!trimmed)
|
|
250
|
-
continue;
|
|
251
|
-
const withoutType = trimmed.replace(/^type\s+/, "");
|
|
252
|
-
const asMatch = withoutType.match(/(\S+)\s+as\s+(\S+)/);
|
|
253
|
-
const localName = asMatch ? asMatch[2] : withoutType;
|
|
254
|
-
usedNames.delete(localName);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const nsGroups = [match[2], match[5]];
|
|
259
|
-
for (const ns of nsGroups) {
|
|
260
|
-
if (ns) {
|
|
261
|
-
const nsMatch = ns.match(/\*\s+as\s+(\w+)/);
|
|
262
|
-
if (nsMatch && nsMatch[1])
|
|
263
|
-
usedNames.delete(nsMatch[1]);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
if (match[3] && match[3] !== "type") {
|
|
267
|
-
usedNames.delete(match[3]);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function removeLocallyDefined(strippedCode, usedNames) {
|
|
272
|
-
const patterns = [
|
|
273
|
-
/(?:export\s+)?(?:async\s+)?function\s+([a-zA-Z_$][\w$]*)/g,
|
|
274
|
-
/(?:export\s+)?(?:const|let|var)\s+([a-zA-Z_$][\w$]*)/g,
|
|
275
|
-
/(?:export\s+)?class\s+([a-zA-Z_$][\w$]*)/g,
|
|
276
|
-
/(?:export\s+)?(?:type|interface)\s+([a-zA-Z_$][\w$]*)/g,
|
|
277
|
-
/(?:export\s+)?enum\s+([a-zA-Z_$][\w$]*)/g
|
|
278
|
-
];
|
|
279
|
-
for (const pattern of patterns) {
|
|
280
|
-
let match;
|
|
281
|
-
while ((match = pattern.exec(strippedCode)) !== null) {
|
|
282
|
-
if (match[1])
|
|
283
|
-
usedNames.delete(match[1]);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function generateImportStatements(usedNames, importMap) {
|
|
288
|
-
const bySource = new Map;
|
|
289
|
-
for (const name of usedNames) {
|
|
290
|
-
const entry = importMap.get(name);
|
|
291
|
-
if (!entry)
|
|
292
|
-
continue;
|
|
293
|
-
if (!bySource.has(entry.from)) {
|
|
294
|
-
bySource.set(entry.from, { types: [], values: [] });
|
|
295
|
-
}
|
|
296
|
-
const group = bySource.get(entry.from);
|
|
297
|
-
const importSpec = entry.as && entry.as !== entry.name ? `${entry.name} as ${entry.as}` : entry.name;
|
|
298
|
-
if (entry.type) {
|
|
299
|
-
group.types.push(importSpec);
|
|
300
|
-
} else {
|
|
301
|
-
group.values.push(importSpec);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const lines = [];
|
|
305
|
-
for (const [source, { types, values }] of bySource) {
|
|
306
|
-
if (values.length > 0) {
|
|
307
|
-
lines.push(`import { ${values.join(", ")} } from '${source}'`);
|
|
308
|
-
}
|
|
309
|
-
if (types.length > 0) {
|
|
310
|
-
lines.push(`import type { ${types.join(", ")} } from '${source}'`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return lines.length > 0 ? `${lines.join(`
|
|
314
|
-
`)}
|
|
315
|
-
` : "";
|
|
316
|
-
}
|
|
317
|
-
function createAutoImportContext(entries) {
|
|
318
|
-
const importMap = new Map;
|
|
319
|
-
for (const entry of entries) {
|
|
320
|
-
const key = entry.as || entry.name;
|
|
321
|
-
if (!importMap.has(key)) {
|
|
322
|
-
importMap.set(key, entry);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
const knownNames = new Set(importMap.keys());
|
|
326
|
-
return {
|
|
327
|
-
importMap,
|
|
328
|
-
knownNames,
|
|
329
|
-
injectImports(code) {
|
|
330
|
-
if (knownNames.size === 0 || !code.trim())
|
|
331
|
-
return { code };
|
|
332
|
-
const stripped = stripLiterals(code);
|
|
333
|
-
const usedNames = detectUsedIdentifiers(stripped, knownNames);
|
|
334
|
-
if (usedNames.size === 0)
|
|
335
|
-
return { code };
|
|
336
|
-
removeAlreadyImported(code, usedNames);
|
|
337
|
-
if (usedNames.size === 0)
|
|
338
|
-
return { code };
|
|
339
|
-
removeLocallyDefined(stripped, usedNames);
|
|
340
|
-
if (usedNames.size === 0)
|
|
341
|
-
return { code };
|
|
342
|
-
const importStatements = generateImportStatements(usedNames, importMap);
|
|
343
|
-
return { code: importStatements + code };
|
|
344
|
-
},
|
|
345
|
-
generateTypeDeclarations() {
|
|
346
|
-
const lines = ["export {}", "declare global {"];
|
|
347
|
-
const sortedEntries = [...importMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
348
|
-
for (const [key, entry] of sortedEntries) {
|
|
349
|
-
if (entry.type) {
|
|
350
|
-
lines.push(` type ${key} = import('${entry.from}')['${entry.name}']`);
|
|
351
|
-
} else {
|
|
352
|
-
lines.push(` const ${key}: typeof import('${entry.from}')['${entry.name}']`);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
lines.push("}");
|
|
356
|
-
return `${lines.join(`
|
|
357
|
-
`)}
|
|
358
|
-
`;
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function resolvePresets(presets) {
|
|
363
|
-
const entries = [];
|
|
364
|
-
for (const preset of presets) {
|
|
365
|
-
for (const imp of preset.imports) {
|
|
366
|
-
if (typeof imp === "string") {
|
|
367
|
-
entries.push({ name: imp, from: preset.from, type: false });
|
|
368
|
-
} else {
|
|
369
|
-
entries.push({ name: imp.name, as: imp.as, from: preset.from, type: false });
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return entries;
|
|
374
|
-
}
|
|
375
|
-
function resolveImports(imports) {
|
|
376
|
-
return imports.map((imp) => ({
|
|
377
|
-
name: imp.name,
|
|
378
|
-
as: imp.as,
|
|
379
|
-
from: imp.from,
|
|
380
|
-
type: imp.type ?? false
|
|
381
|
-
}));
|
|
382
|
-
}
|
|
383
|
-
async function scanDirExportsDetailed(dir, options) {
|
|
384
|
-
const exports = [];
|
|
385
|
-
const includeTypes = options?.types ?? true;
|
|
386
|
-
try {
|
|
387
|
-
const glob = new Glob("**/*.{ts,tsx,js,jsx}");
|
|
388
|
-
for await (const file of glob.scan({
|
|
389
|
-
cwd: dir,
|
|
390
|
-
absolute: true,
|
|
391
|
-
onlyFiles: true,
|
|
392
|
-
followSymlinks: false
|
|
393
|
-
})) {
|
|
394
|
-
try {
|
|
395
|
-
if (file.includes("node_modules") || file.endsWith(".d.ts")) {
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const content = await Bun.file(file).text();
|
|
399
|
-
for (const match of content.matchAll(/export\s+async\s+function\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
400
|
-
if (match[1]) {
|
|
401
|
-
exports.push({ name: match[1], file, isType: false, isDefault: false });
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
for (const match of content.matchAll(/export\s+function\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
405
|
-
if (match[1]) {
|
|
406
|
-
exports.push({ name: match[1], file, isType: false, isDefault: false });
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
for (const match of content.matchAll(/export\s+(?:const|let|var)\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
410
|
-
if (match[1]) {
|
|
411
|
-
exports.push({ name: match[1], file, isType: false, isDefault: false });
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
for (const match of content.matchAll(/export\s+class\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
415
|
-
if (match[1]) {
|
|
416
|
-
exports.push({ name: match[1], file, isType: false, isDefault: false });
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (includeTypes) {
|
|
420
|
-
for (const match of content.matchAll(/export\s+(?:type|interface)\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
421
|
-
if (match[1]) {
|
|
422
|
-
exports.push({ name: match[1], file, isType: true, isDefault: false });
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
for (const match of content.matchAll(/export\s+\{([^}]+)\}/g)) {
|
|
427
|
-
if (match[1]) {
|
|
428
|
-
const names = match[1].split(",").map((n) => {
|
|
429
|
-
const trimmed = n.trim();
|
|
430
|
-
const asMatch = trimmed.match(/(\S+)\s+as\s+(\S+)/);
|
|
431
|
-
return asMatch ? asMatch[2] : trimmed;
|
|
432
|
-
}).filter((n) => n && !n.includes("*"));
|
|
433
|
-
for (const name of names) {
|
|
434
|
-
exports.push({ name, file, isType: false, isDefault: false });
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
for (const match of content.matchAll(/export\s+default\s+(?:async\s+)?(?:function|class)\s+([a-zA-Z_$][\w$]*)/g)) {
|
|
439
|
-
if (match[1]) {
|
|
440
|
-
exports.push({ name: match[1], file, isType: false, isDefault: true });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
} catch (error) {
|
|
444
|
-
console.warn(`Warning: Failed to process file ${file}:`, error instanceof Error ? error.message : error);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.error(`Error scanning directory ${dir}:`, error instanceof Error ? error.message : error);
|
|
449
|
-
throw new Error(`Failed to scan directory ${dir}: ${error instanceof Error ? error.message : String(error)}`);
|
|
450
|
-
}
|
|
451
|
-
return exports;
|
|
452
|
-
}
|
|
453
|
-
async function generateRuntimeIndex(dirs, outputPath) {
|
|
454
|
-
const allExports = [];
|
|
455
|
-
for (const dir of dirs) {
|
|
456
|
-
const dirPath = typeof dir === "string" ? dir : dir.path;
|
|
457
|
-
const types = typeof dir === "object" ? dir.types : true;
|
|
458
|
-
const exports = await scanDirExportsDetailed(dirPath, { types });
|
|
459
|
-
allExports.push(...exports);
|
|
460
|
-
}
|
|
461
|
-
const exportsByFile = new Map;
|
|
462
|
-
for (const exp of allExports) {
|
|
463
|
-
const existing = exportsByFile.get(exp.file) || [];
|
|
464
|
-
existing.push(exp);
|
|
465
|
-
exportsByFile.set(exp.file, existing);
|
|
466
|
-
}
|
|
467
|
-
const lines = [GENERATED_COMMENT];
|
|
468
|
-
for (const [file, exports] of exportsByFile) {
|
|
469
|
-
const relativePath = path.relative(path.dirname(outputPath), file).replace(/\\/g, "/");
|
|
470
|
-
const importPath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
471
|
-
const cleanPath = importPath.replace(/\.tsx?$/, "");
|
|
472
|
-
const valueExports = exports.filter((e) => !e.isType && !e.isDefault);
|
|
473
|
-
const typeExports = exports.filter((e) => e.isType);
|
|
474
|
-
const defaultExports = exports.filter((e) => e.isDefault);
|
|
475
|
-
if (valueExports.length > 0) {
|
|
476
|
-
lines.push(`export { ${valueExports.map((e) => e.name).join(", ")} } from '${cleanPath}'`);
|
|
477
|
-
}
|
|
478
|
-
if (typeExports.length > 0) {
|
|
479
|
-
lines.push(`export type { ${typeExports.map((e) => e.name).join(", ")} } from '${cleanPath}'`);
|
|
480
|
-
}
|
|
481
|
-
for (const def of defaultExports) {
|
|
482
|
-
const local = `_${def.name}`;
|
|
483
|
-
lines.push(`const ${local} = (await import('${cleanPath}')).default`);
|
|
484
|
-
lines.push(`export { ${local} as ${def.name} }`);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
const content = `${lines.join(`
|
|
488
|
-
`)}
|
|
489
|
-
`;
|
|
490
|
-
await Bun.write(outputPath, content);
|
|
491
|
-
return { exports: allExports, content };
|
|
492
|
-
}
|
|
493
|
-
async function generateGlobalsScript(dirs, outputPath, indexPath) {
|
|
494
|
-
const allExports = [];
|
|
495
|
-
for (const dir of dirs) {
|
|
496
|
-
const dirPath = typeof dir === "string" ? dir : dir.path;
|
|
497
|
-
const types = typeof dir === "object" ? dir.types : true;
|
|
498
|
-
const exports = await scanDirExportsDetailed(dirPath, { types });
|
|
499
|
-
allExports.push(...exports);
|
|
500
|
-
}
|
|
501
|
-
const valueExports = allExports.filter((e) => !e.isType);
|
|
502
|
-
const relativePath = path.relative(path.dirname(outputPath), indexPath).replace(/\\/g, "/");
|
|
503
|
-
const importPath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
504
|
-
const cleanPath = importPath.replace(/\.tsx?$/, "");
|
|
505
|
-
const lines = [
|
|
506
|
-
GENERATED_COMMENT,
|
|
507
|
-
`// This file injects auto-imported functions into the global scope`,
|
|
508
|
-
`// Import this file early in your application startup`,
|
|
509
|
-
``,
|
|
510
|
-
`import * as autoImports from '${cleanPath}'`,
|
|
511
|
-
``,
|
|
512
|
-
`// Inject into globalThis for runtime access`,
|
|
513
|
-
`Object.assign(globalThis, autoImports)`,
|
|
514
|
-
``,
|
|
515
|
-
`// TypeScript declarations`,
|
|
516
|
-
`declare global {`
|
|
517
|
-
];
|
|
518
|
-
for (const exp of valueExports) {
|
|
519
|
-
lines.push(` const ${exp.name}: typeof autoImports.${exp.name}`);
|
|
520
|
-
}
|
|
521
|
-
lines.push(`}`);
|
|
522
|
-
lines.push(``);
|
|
523
|
-
lines.push(`export {}`);
|
|
524
|
-
lines.push(``);
|
|
525
|
-
const content = lines.join(`
|
|
526
|
-
`);
|
|
527
|
-
await Bun.write(outputPath, content);
|
|
528
|
-
return content;
|
|
529
|
-
}
|
|
530
|
-
function autoImports(options) {
|
|
531
|
-
return {
|
|
532
|
-
name: "bun-plugin-auto-imports",
|
|
533
|
-
async setup(builder) {
|
|
534
|
-
try {
|
|
535
|
-
if (options.dirs && !Array.isArray(options.dirs)) {
|
|
536
|
-
throw new Error("options.dirs must be an array");
|
|
537
|
-
}
|
|
538
|
-
const allEntries = [];
|
|
539
|
-
if (options.presets) {
|
|
540
|
-
allEntries.push(...resolvePresets(options.presets));
|
|
541
|
-
}
|
|
542
|
-
if (options.imports) {
|
|
543
|
-
allEntries.push(...resolveImports(options.imports));
|
|
544
|
-
}
|
|
545
|
-
const dtsPath = path.resolve(options.dts ?? "./auto-imports.d.ts");
|
|
546
|
-
const dtsDir = path.dirname(dtsPath);
|
|
547
|
-
if (options.dirs) {
|
|
548
|
-
for (const dir of options.dirs) {
|
|
549
|
-
const dirPath = typeof dir === "string" ? dir : ("path" in dir) ? dir.path : dir;
|
|
550
|
-
if (!dirPath) {
|
|
551
|
-
console.warn("Warning: Invalid directory configuration found, skipping:", dir);
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
const exports = await scanDirExportsDetailed(dirPath);
|
|
555
|
-
for (const exp of exports) {
|
|
556
|
-
const relativePath = `./${path.relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.tsx?$/, "")}`;
|
|
557
|
-
allEntries.push({
|
|
558
|
-
name: exp.name,
|
|
559
|
-
from: relativePath,
|
|
560
|
-
type: exp.isType
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
const context = createAutoImportContext(allEntries);
|
|
566
|
-
const dtsContent = context.generateTypeDeclarations();
|
|
567
|
-
await Bun.write(options.dts ?? "./auto-imports.d.ts", GENERATED_COMMENT + dtsContent);
|
|
568
|
-
if (options.eslint?.enabled === true) {
|
|
569
|
-
const eslintOptions = {
|
|
570
|
-
enabled: true,
|
|
571
|
-
filepath: options.eslint.filepath ?? "./.eslint-auto-import.json",
|
|
572
|
-
globalsPropValue: options.eslint.globalsPropValue
|
|
573
|
-
};
|
|
574
|
-
const eslintContent = generateESLintGlobals(GENERATED_COMMENT + dtsContent, eslintOptions);
|
|
575
|
-
await Bun.write(eslintOptions.filepath ?? "./.eslint-auto-import.json", eslintContent);
|
|
576
|
-
}
|
|
577
|
-
builder.onLoad({ filter: /.*/ }, async (args) => {
|
|
578
|
-
const fileContent = await Bun.file(args.path).text();
|
|
579
|
-
const result = context.injectImports(fileContent);
|
|
580
|
-
return {
|
|
581
|
-
contents: result.code,
|
|
582
|
-
loader: getLoader(args.path)
|
|
583
|
-
};
|
|
584
|
-
});
|
|
585
|
-
} catch (error) {
|
|
586
|
-
console.error("Error setting up auto-imports plugin:", error instanceof Error ? error.message : error);
|
|
587
|
-
throw new Error(`Failed to set up auto-imports plugin: ${error instanceof Error ? error.message : String(error)}`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// src/imports.ts
|
|
594
|
-
import { globSync } from "@stacksjs/storage";
|
|
595
|
-
var OPTIONAL_MODEL_MODULES = {
|
|
596
|
-
commerce: ["config/commerce.ts"],
|
|
597
|
-
Content: ["config/cms.ts", "config/blog.ts"],
|
|
598
|
-
realtime: ["config/realtime.ts"]
|
|
599
|
-
};
|
|
600
|
-
function configEnabled(configRelPaths) {
|
|
601
|
-
return configRelPaths.some((rel) => existsSync(path2.projectPath(rel)));
|
|
602
|
-
}
|
|
603
|
-
function resolveDefaultModelDirs() {
|
|
604
|
-
const root = path2.storagePath("framework/defaults/app/Models");
|
|
605
|
-
const dirs = [root];
|
|
606
|
-
for (const [subdir, configPaths] of Object.entries(OPTIONAL_MODEL_MODULES)) {
|
|
607
|
-
if (configEnabled(configPaths))
|
|
608
|
-
dirs.push(`${root}/${subdir}`);
|
|
609
|
-
}
|
|
610
|
-
return dirs;
|
|
611
|
-
}
|
|
612
|
-
function scanDefineModelExports(dir, opts = {}) {
|
|
613
|
-
const { recursive = true } = opts;
|
|
614
|
-
let files = [];
|
|
615
|
-
try {
|
|
616
|
-
const pattern = recursive ? `${dir}/**/*.ts` : `${dir}/*.ts`;
|
|
617
|
-
files = globSync(pattern, { ignore: ["**/*.d.ts", "**/index.ts", "**/README*"] });
|
|
618
|
-
} catch {
|
|
619
|
-
return [];
|
|
620
|
-
}
|
|
621
|
-
const exports = [];
|
|
622
|
-
const seen = new Set;
|
|
623
|
-
for (const file of files) {
|
|
624
|
-
const basename = file.split("/").pop()?.replace(".ts", "") || "";
|
|
625
|
-
if (basename && !seen.has(basename)) {
|
|
626
|
-
seen.add(basename);
|
|
627
|
-
exports.push({ name: basename, file, isDefault: true });
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
return exports;
|
|
631
|
-
}
|
|
632
|
-
var GLOBAL_SHADOW_BLOCKLIST = new Set([
|
|
633
|
-
"Error",
|
|
634
|
-
"Request",
|
|
635
|
-
"Response",
|
|
636
|
-
"URL",
|
|
637
|
-
"Map",
|
|
638
|
-
"Set",
|
|
639
|
-
"Object",
|
|
640
|
-
"Array",
|
|
641
|
-
"Number",
|
|
642
|
-
"String",
|
|
643
|
-
"Date",
|
|
644
|
-
"Promise",
|
|
645
|
-
"Symbol"
|
|
646
|
-
]);
|
|
647
|
-
async function generateDefineModelIndex(entries, outputPath) {
|
|
648
|
-
const lines = ["// Generated by bun-plugin-auto-imports"];
|
|
649
|
-
const seen = new Set;
|
|
650
|
-
for (const entry of entries) {
|
|
651
|
-
const dir = typeof entry === "string" ? entry : entry.dir;
|
|
652
|
-
const recursive = typeof entry === "string" ? true : entry.recursive;
|
|
653
|
-
let files = [];
|
|
654
|
-
try {
|
|
655
|
-
const pattern = recursive ? `${dir}/**/*.ts` : `${dir}/*.ts`;
|
|
656
|
-
files = globSync(pattern, { ignore: ["**/*.d.ts", "**/index.ts", "**/README*"] });
|
|
657
|
-
} catch {
|
|
658
|
-
continue;
|
|
659
|
-
}
|
|
660
|
-
for (const file of files) {
|
|
661
|
-
const basename = file.split("/").pop()?.replace(".ts", "") || "";
|
|
662
|
-
if (!basename || seen.has(basename))
|
|
663
|
-
continue;
|
|
664
|
-
seen.add(basename);
|
|
665
|
-
const relativePath = relative(dirname(outputPath), file).replace(/\.ts$/, "");
|
|
666
|
-
if (GLOBAL_SHADOW_BLOCKLIST.has(basename)) {
|
|
667
|
-
lines.push(`// Skipped '${basename}' \u2014 would shadow a built-in global. Import directly if needed.`);
|
|
668
|
-
lines.push(`// export { default as ${basename} } from '${relativePath}'`);
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
lines.push(`export { default as ${basename} } from '${relativePath}'`);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
await Bun.write(outputPath, lines.join(`
|
|
675
|
-
`) + `
|
|
676
|
-
`);
|
|
677
|
-
}
|
|
678
|
-
async function generateAutoImportFiles() {
|
|
679
|
-
const userFunctionsPath = path2.resourcesPath("functions");
|
|
680
|
-
const defaultFunctionsPath = path2.storagePath("framework/defaults/functions");
|
|
681
|
-
const functionsPath = userFunctionsPath;
|
|
682
|
-
const outputDir = path2.storagePath("framework/auto-imports");
|
|
683
|
-
const userModelsPath = path2.userModelsPath();
|
|
684
|
-
const defaultModelDirs = resolveDefaultModelDirs();
|
|
685
|
-
const [defaultsRoot = path2.storagePath("framework/defaults/app/Models"), ...enabledSubdirs] = defaultModelDirs;
|
|
686
|
-
const userJobsPath = path2.userJobsPath();
|
|
687
|
-
const userControllersPath = path2.userControllersPath();
|
|
688
|
-
const defaultControllersPath = path2.storagePath("framework/defaults/app/Controllers");
|
|
689
|
-
await Bun.write(`${outputDir}/.gitkeep`, "");
|
|
690
|
-
const functionsIndexPath = `${outputDir}/functions.ts`;
|
|
691
|
-
await generateRuntimeIndex([userFunctionsPath, defaultFunctionsPath], functionsIndexPath);
|
|
692
|
-
const modelsIndexPath = `${outputDir}/models.ts`;
|
|
693
|
-
const modelScan = [
|
|
694
|
-
userModelsPath,
|
|
695
|
-
{ dir: defaultsRoot, recursive: false },
|
|
696
|
-
...defaultModelDirs.slice(1).map((d) => ({ dir: d, recursive: true }))
|
|
697
|
-
];
|
|
698
|
-
await generateDefineModelIndex(modelScan, modelsIndexPath);
|
|
699
|
-
const jobsIndexPath = `${outputDir}/jobs.ts`;
|
|
700
|
-
await generateDefineModelIndex([userJobsPath], jobsIndexPath);
|
|
701
|
-
const controllersIndexPath = `${outputDir}/controllers.ts`;
|
|
702
|
-
await generateDefineModelIndex([userControllersPath, defaultControllersPath], controllersIndexPath);
|
|
703
|
-
const combinedContent = `// Generated by bun-plugin-auto-imports
|
|
704
|
-
export * from './functions'
|
|
705
|
-
export * from './models'
|
|
706
|
-
export * from './jobs'
|
|
707
|
-
export * from './controllers'
|
|
708
|
-
`;
|
|
709
|
-
await Bun.write(`${outputDir}/index.ts`, combinedContent);
|
|
710
|
-
const globalsPath = `${outputDir}/globals.ts`;
|
|
711
|
-
await generateGlobalsScript([functionsPath], globalsPath, `${outputDir}/index.ts`);
|
|
712
|
-
log2.debug("Auto-import files generated successfully");
|
|
713
|
-
}
|
|
714
|
-
function initiateImports() {
|
|
715
|
-
const functionsPath = path2.resourcesPath("functions");
|
|
716
|
-
const defaultFunctionsPath = path2.storagePath("framework/defaults/functions");
|
|
717
|
-
const userModelsPath = path2.userModelsPath();
|
|
718
|
-
const defaultModelDirs = resolveDefaultModelDirs();
|
|
719
|
-
const [defaultsRoot = path2.storagePath("framework/defaults/app/Models"), ...enabledSubdirs] = defaultModelDirs;
|
|
720
|
-
const userJobsPath = path2.userJobsPath();
|
|
721
|
-
const userControllersPath = path2.userControllersPath();
|
|
722
|
-
const defaultControllersPath = path2.storagePath("framework/defaults/app/Controllers");
|
|
723
|
-
const defineModelExports = [
|
|
724
|
-
...scanDefineModelExports(userModelsPath),
|
|
725
|
-
...scanDefineModelExports(defaultsRoot, { recursive: false }),
|
|
726
|
-
...enabledSubdirs.flatMap((d) => scanDefineModelExports(d))
|
|
727
|
-
];
|
|
728
|
-
const jobExports = scanDefineModelExports(userJobsPath);
|
|
729
|
-
const seen = new Set;
|
|
730
|
-
const uniqueDefineModelExports = defineModelExports.filter((exp) => {
|
|
731
|
-
if (seen.has(exp.name))
|
|
732
|
-
return false;
|
|
733
|
-
seen.add(exp.name);
|
|
734
|
-
return true;
|
|
735
|
-
});
|
|
736
|
-
const dtsDir = dirname(path2.storagePath("framework/types/server-auto-imports.d.ts"));
|
|
737
|
-
const defineModelImports = uniqueDefineModelExports.map((exp) => ({
|
|
738
|
-
from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
|
|
739
|
-
name: "default",
|
|
740
|
-
as: exp.name
|
|
741
|
-
}));
|
|
742
|
-
const jobImports = jobExports.map((exp) => ({
|
|
743
|
-
from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
|
|
744
|
-
name: "default",
|
|
745
|
-
as: exp.name
|
|
746
|
-
}));
|
|
747
|
-
const controllerExports = [
|
|
748
|
-
...scanDefineModelExports(userControllersPath),
|
|
749
|
-
...scanDefineModelExports(defaultControllersPath)
|
|
750
|
-
];
|
|
751
|
-
const seenControllers = new Set;
|
|
752
|
-
const uniqueControllerExports = controllerExports.filter((exp) => {
|
|
753
|
-
if (seenControllers.has(exp.name))
|
|
754
|
-
return false;
|
|
755
|
-
seenControllers.add(exp.name);
|
|
756
|
-
return true;
|
|
757
|
-
});
|
|
758
|
-
const controllerImports = uniqueControllerExports.map((exp) => ({
|
|
759
|
-
from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
|
|
760
|
-
name: "default",
|
|
761
|
-
as: exp.name
|
|
762
|
-
}));
|
|
763
|
-
const options = {
|
|
764
|
-
dts: path2.storagePath("framework/types/server-auto-imports.d.ts"),
|
|
765
|
-
imports: [...defineModelImports, ...jobImports, ...controllerImports],
|
|
766
|
-
dirs: [functionsPath, defaultFunctionsPath],
|
|
767
|
-
eslint: {
|
|
768
|
-
enabled: true,
|
|
769
|
-
filepath: path2.storagePath("framework/server-auto-imports.json")
|
|
770
|
-
}
|
|
771
|
-
};
|
|
772
|
-
plugin(autoImports(options));
|
|
773
|
-
generateAutoImportFiles().catch((err) => {
|
|
774
|
-
console.error("[Server] Failed to generate auto-import files:", err);
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
async function injectGlobalAutoImports() {
|
|
778
|
-
if (globalThis.__stacksAutoImportsInjected)
|
|
779
|
-
return;
|
|
780
|
-
globalThis.__stacksAutoImportsInjected = true;
|
|
781
|
-
const errors = [];
|
|
782
|
-
const primitiveModules = [
|
|
783
|
-
["@stacksjs/types", ["Every", "ExitCode"]],
|
|
784
|
-
["@stacksjs/path", ["path"]],
|
|
785
|
-
["@stacksjs/error-handling", ["HttpError", "handleError"]],
|
|
786
|
-
["@stacksjs/logging", ["log"]],
|
|
787
|
-
["@stacksjs/config", ["config"]],
|
|
788
|
-
["@stacksjs/validation", ["schema"]],
|
|
789
|
-
["@stacksjs/router", ["response", "request", "route", "Middleware", "url"]],
|
|
790
|
-
["@stacksjs/storage", ["storage", "fs"]],
|
|
791
|
-
["@stacksjs/orm", ["defineModel", "toAttrs"]],
|
|
792
|
-
["@stacksjs/database", ["db", "sql"]],
|
|
793
|
-
["@stacksjs/email", ["mail", "template"]],
|
|
794
|
-
["@stacksjs/queue", ["Job"]],
|
|
795
|
-
["@stacksjs/scheduler", ["schedule"]],
|
|
796
|
-
["@stacksjs/actions", ["Action"]],
|
|
797
|
-
["@stacksjs/auth", ["Auth", "register", "sessionCheck"]],
|
|
798
|
-
["@stacksjs/events", ["dispatch", "listen", "emitter"]],
|
|
799
|
-
["@stacksjs/security", ["makeHash", "verifyHash"]],
|
|
800
|
-
["@stacksjs/collections", ["collect"]],
|
|
801
|
-
["@stacksjs/cli", ["quotes"]],
|
|
802
|
-
["@stacksjs/notifications", ["notify", "useNotification", "useEmail", "useSMS", "useChat", "useDatabase"]],
|
|
803
|
-
["@stacksjs/realtime", ["emit", "emitToUser", "emitToUsers", "createChannel", "dispatchBroadcast"]],
|
|
804
|
-
["@stacksjs/i18n", ["I18n", "t", "tc", "te", "setLocale", "getLocale"]],
|
|
805
|
-
["@stacksjs/stx", ["state", "derived", "effect"]],
|
|
806
|
-
["@stacksjs/browser", ["useDark", "usePreferredDark", "useToggle", "useStorage"]]
|
|
807
|
-
];
|
|
808
|
-
const importWithTimeout = async (pkg) => {
|
|
809
|
-
return Promise.race([
|
|
810
|
-
import(pkg),
|
|
811
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(`auto-import timed out: ${pkg}`)), 4000))
|
|
812
|
-
]);
|
|
813
|
-
};
|
|
814
|
-
await Promise.all(primitiveModules.map(async ([pkg, names]) => {
|
|
815
|
-
try {
|
|
816
|
-
const mod = await importWithTimeout(pkg);
|
|
817
|
-
for (const name of names) {
|
|
818
|
-
if (mod[name] !== undefined)
|
|
819
|
-
globalThis[name] = mod[name];
|
|
820
|
-
}
|
|
821
|
-
} catch (err) {
|
|
822
|
-
errors.push(err);
|
|
823
|
-
}
|
|
824
|
-
}));
|
|
825
|
-
try {
|
|
826
|
-
const { ensureLocalesLoaded } = await import("@stacksjs/i18n");
|
|
827
|
-
await ensureLocalesLoaded();
|
|
828
|
-
} catch (err) {
|
|
829
|
-
errors.push(err);
|
|
830
|
-
}
|
|
831
|
-
try {
|
|
832
|
-
const autoImportsPath = path2.storagePath("framework/auto-imports/index.ts");
|
|
833
|
-
const autoImports2 = await import(autoImportsPath);
|
|
834
|
-
Object.assign(globalThis, autoImports2);
|
|
835
|
-
} catch (err) {
|
|
836
|
-
errors.push(err);
|
|
837
|
-
}
|
|
838
|
-
if (errors.length) {
|
|
839
|
-
for (const err of errors)
|
|
840
|
-
console.warn("[auto-imports]", err.message);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
// src/maintenance.ts
|
|
844
|
-
import { log as log3 } from "@stacksjs/logging";
|
|
845
|
-
import * as p from "@stacksjs/path";
|
|
846
|
-
var DEFAULT_MAINTENANCE_PAYLOAD = {
|
|
847
|
-
mode: "maintenance",
|
|
848
|
-
status: 503,
|
|
849
|
-
message: "We are currently performing maintenance. Please check back soon."
|
|
850
|
-
};
|
|
851
|
-
var DEFAULT_COMING_SOON_PAYLOAD = {
|
|
852
|
-
mode: "coming-soon",
|
|
853
|
-
status: 200,
|
|
854
|
-
message: "Stacks is setting up camp. Check back soon for the public launch.",
|
|
855
|
-
redirect: "/coming-soon"
|
|
856
|
-
};
|
|
857
|
-
function defaultsForMode(mode) {
|
|
858
|
-
return mode === "coming-soon" ? DEFAULT_COMING_SOON_PAYLOAD : DEFAULT_MAINTENANCE_PAYLOAD;
|
|
859
|
-
}
|
|
860
|
-
function maintenanceFilePath() {
|
|
861
|
-
return p.storagePath("framework/down");
|
|
862
|
-
}
|
|
863
|
-
function comingSoonFilePath() {
|
|
864
|
-
return p.storagePath("framework/coming-soon");
|
|
865
|
-
}
|
|
866
|
-
function siteModeFilePath(mode) {
|
|
867
|
-
return mode === "coming-soon" ? comingSoonFilePath() : maintenanceFilePath();
|
|
868
|
-
}
|
|
869
|
-
async function isDownForMaintenance() {
|
|
870
|
-
try {
|
|
871
|
-
const file = Bun.file(maintenanceFilePath());
|
|
872
|
-
return await file.exists();
|
|
873
|
-
} catch {
|
|
874
|
-
return false;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
async function isComingSoon() {
|
|
878
|
-
try {
|
|
879
|
-
const file = Bun.file(comingSoonFilePath());
|
|
880
|
-
return await file.exists();
|
|
881
|
-
} catch {
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
async function maintenancePayload() {
|
|
886
|
-
return siteModePayload("maintenance");
|
|
887
|
-
}
|
|
888
|
-
async function comingSoonPayload() {
|
|
889
|
-
return siteModePayload("coming-soon");
|
|
890
|
-
}
|
|
891
|
-
async function siteModePayload(mode) {
|
|
892
|
-
try {
|
|
893
|
-
const file = Bun.file(siteModeFilePath(mode));
|
|
894
|
-
if (!await file.exists()) {
|
|
895
|
-
return null;
|
|
896
|
-
}
|
|
897
|
-
const content = await file.text();
|
|
898
|
-
return {
|
|
899
|
-
...defaultsForMode(mode),
|
|
900
|
-
...JSON.parse(content),
|
|
901
|
-
mode
|
|
902
|
-
};
|
|
903
|
-
} catch {
|
|
904
|
-
return null;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
async function activeSiteModePayload() {
|
|
908
|
-
return await maintenancePayload() ?? await comingSoonPayload() ?? envSiteModePayload();
|
|
909
|
-
}
|
|
910
|
-
function envSiteModePayload() {
|
|
911
|
-
if (isTruthy(process.env.APP_MAINTENANCE)) {
|
|
912
|
-
return {
|
|
913
|
-
...DEFAULT_MAINTENANCE_PAYLOAD,
|
|
914
|
-
mode: "maintenance",
|
|
915
|
-
time: Date.now(),
|
|
916
|
-
secret: process.env.APP_MAINTENANCE_SECRET || undefined
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
if (isTruthy(process.env.APP_COMING_SOON)) {
|
|
920
|
-
return {
|
|
921
|
-
...DEFAULT_COMING_SOON_PAYLOAD,
|
|
922
|
-
mode: "coming-soon",
|
|
923
|
-
time: Date.now(),
|
|
924
|
-
secret: process.env.APP_COMING_SOON_SECRET || undefined
|
|
925
|
-
};
|
|
926
|
-
}
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
|
-
function isTruthy(value) {
|
|
930
|
-
return ["1", "true", "yes", "on"].includes(String(value || "").toLowerCase());
|
|
931
|
-
}
|
|
932
|
-
async function down(options = {}) {
|
|
933
|
-
const payload = {
|
|
934
|
-
...DEFAULT_MAINTENANCE_PAYLOAD,
|
|
935
|
-
...options,
|
|
936
|
-
mode: "maintenance",
|
|
937
|
-
time: Date.now()
|
|
938
|
-
};
|
|
939
|
-
const frameworkDir = p.storagePath("framework");
|
|
940
|
-
const { mkdirSync, existsSync: existsSync2 } = await import("@stacksjs/storage");
|
|
941
|
-
if (!existsSync2(frameworkDir)) {
|
|
942
|
-
mkdirSync(frameworkDir, { recursive: true });
|
|
943
|
-
}
|
|
944
|
-
await Bun.write(maintenanceFilePath(), JSON.stringify(payload, null, 2));
|
|
945
|
-
log3.info("Application is now in maintenance mode.");
|
|
946
|
-
if (payload.secret) {
|
|
947
|
-
log3.info("Maintenance bypass secret has been configured");
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
async function comingSoon(options = {}) {
|
|
951
|
-
const payload = {
|
|
952
|
-
...DEFAULT_COMING_SOON_PAYLOAD,
|
|
953
|
-
...options,
|
|
954
|
-
mode: "coming-soon",
|
|
955
|
-
time: Date.now()
|
|
956
|
-
};
|
|
957
|
-
const frameworkDir = p.storagePath("framework");
|
|
958
|
-
const { mkdirSync, existsSync: existsSync2 } = await import("@stacksjs/storage");
|
|
959
|
-
if (!existsSync2(frameworkDir)) {
|
|
960
|
-
mkdirSync(frameworkDir, { recursive: true });
|
|
961
|
-
}
|
|
962
|
-
await Bun.write(comingSoonFilePath(), JSON.stringify(payload, null, 2));
|
|
963
|
-
log3.info("Application is now in coming soon mode.");
|
|
964
|
-
if (payload.secret) {
|
|
965
|
-
log3.info("Coming soon bypass secret has been configured");
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
async function up() {
|
|
969
|
-
const { unlinkSync, existsSync: existsSync2 } = await import("fs");
|
|
970
|
-
const filePath = maintenanceFilePath();
|
|
971
|
-
if (existsSync2(filePath)) {
|
|
972
|
-
unlinkSync(filePath);
|
|
973
|
-
log3.info("Application is now live.");
|
|
974
|
-
} else {
|
|
975
|
-
log3.info("Application is already live.");
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
async function launch() {
|
|
979
|
-
const { unlinkSync, existsSync: existsSync2 } = await import("fs");
|
|
980
|
-
const filePath = comingSoonFilePath();
|
|
981
|
-
if (existsSync2(filePath)) {
|
|
982
|
-
unlinkSync(filePath);
|
|
983
|
-
log3.info("Application is out of coming soon mode.");
|
|
984
|
-
} else {
|
|
985
|
-
log3.info("Application is not in coming soon mode.");
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
function isAllowedIp(ip, allowed = []) {
|
|
989
|
-
if (allowed.length === 0) {
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
const localhostIps = ["127.0.0.1", "::1", "localhost"];
|
|
993
|
-
if (localhostIps.includes(ip)) {
|
|
994
|
-
return true;
|
|
995
|
-
}
|
|
996
|
-
return allowed.includes(ip);
|
|
997
|
-
}
|
|
998
|
-
function bypassCookieName(mode = "maintenance") {
|
|
999
|
-
return mode === "coming-soon" ? "stacks_coming_soon_bypass" : "stacks_maintenance_bypass";
|
|
1000
|
-
}
|
|
1001
|
-
function hasValidBypassCookie(cookies, secret, mode = "maintenance") {
|
|
1002
|
-
const bypassCookie = cookies[bypassCookieName(mode)];
|
|
1003
|
-
return bypassCookie === secret;
|
|
1004
|
-
}
|
|
1005
|
-
function isSecretPath(path3, secret) {
|
|
1006
|
-
return path3 === `/${secret}` || path3.startsWith(`/${secret}/`);
|
|
1007
|
-
}
|
|
1008
|
-
function maintenanceHtml(payload) {
|
|
1009
|
-
const mode = payload.mode ?? "maintenance";
|
|
1010
|
-
const defaults = defaultsForMode(mode);
|
|
1011
|
-
const message = escapeHtml(payload.message || defaults.message || "");
|
|
1012
|
-
const title = escapeHtml(payload.title || (mode === "coming-soon" ? "Opening Soon" : "Trail Maintenance"));
|
|
1013
|
-
const eyebrow = mode === "coming-soon" ? "Stacks basecamp" : "Service notice";
|
|
1014
|
-
const lead = mode === "coming-soon" ? "The public trailhead is almost ready." : "The route is temporarily closed while the crew improves the path.";
|
|
1015
|
-
return `<!DOCTYPE html>
|
|
1016
|
-
<html lang="en">
|
|
1017
|
-
<head>
|
|
1018
|
-
<meta charset="UTF-8">
|
|
1019
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1020
|
-
<title>${title}</title>
|
|
1021
|
-
<style>
|
|
1022
|
-
@font-face {
|
|
1023
|
-
font-display: swap;
|
|
1024
|
-
font-family: "Campmate Script";
|
|
1025
|
-
src: url("/assets/fonts/nps/CampmateScript-Regular.woff2") format("woff2");
|
|
1026
|
-
}
|
|
1027
|
-
@font-face {
|
|
1028
|
-
font-display: swap;
|
|
1029
|
-
font-family: "Switchback";
|
|
1030
|
-
src: url("/assets/fonts/nps/Switchback-Regular.woff2") format("woff2");
|
|
1031
|
-
}
|
|
1032
|
-
@font-face {
|
|
1033
|
-
font-display: swap;
|
|
1034
|
-
font-family: "NPS 2026";
|
|
1035
|
-
font-weight: 100 900;
|
|
1036
|
-
src: url("/assets/fonts/nps/NPS_2026-variable.woff2") format("woff2");
|
|
1037
|
-
}
|
|
1038
|
-
* {
|
|
1039
|
-
margin: 0;
|
|
1040
|
-
padding: 0;
|
|
1041
|
-
box-sizing: border-box;
|
|
1042
|
-
}
|
|
1043
|
-
body {
|
|
1044
|
-
font-family: "Switchback", ui-sans-serif, system-ui, sans-serif;
|
|
1045
|
-
min-height: 100vh;
|
|
1046
|
-
display: flex;
|
|
1047
|
-
align-items: center;
|
|
1048
|
-
justify-content: center;
|
|
1049
|
-
background:
|
|
1050
|
-
linear-gradient(180deg, rgba(10, 28, 18, 0.78), rgba(10, 28, 18, 0.94)),
|
|
1051
|
-
url("/assets/images/topography.svg") center / 760px auto,
|
|
1052
|
-
#0d1e16;
|
|
1053
|
-
color: #fff7e1;
|
|
1054
|
-
padding: 20px;
|
|
1055
|
-
}
|
|
1056
|
-
.container {
|
|
1057
|
-
position: relative;
|
|
1058
|
-
width: min(760px, 100%);
|
|
1059
|
-
overflow: hidden;
|
|
1060
|
-
border: 1px solid rgba(255, 240, 200, 0.28);
|
|
1061
|
-
border-top: 6px solid #df9a2f;
|
|
1062
|
-
border-radius: 8px;
|
|
1063
|
-
padding: clamp(2rem, 7vw, 4.5rem);
|
|
1064
|
-
background:
|
|
1065
|
-
linear-gradient(180deg, rgba(27, 65, 40, 0.86), rgba(12, 31, 21, 0.96)),
|
|
1066
|
-
#163824;
|
|
1067
|
-
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.38);
|
|
1068
|
-
}
|
|
1069
|
-
.container::after {
|
|
1070
|
-
position: absolute;
|
|
1071
|
-
inset: auto 0 0;
|
|
1072
|
-
height: 44%;
|
|
1073
|
-
content: "";
|
|
1074
|
-
background: url("/assets/images/park-ridge.svg") center bottom / cover no-repeat;
|
|
1075
|
-
opacity: 0.34;
|
|
1076
|
-
pointer-events: none;
|
|
1077
|
-
}
|
|
1078
|
-
.eyebrow {
|
|
1079
|
-
position: relative;
|
|
1080
|
-
z-index: 1;
|
|
1081
|
-
display: flex;
|
|
1082
|
-
gap: .75rem;
|
|
1083
|
-
align-items: center;
|
|
1084
|
-
color: #aac47d;
|
|
1085
|
-
font-family: "Switchback", ui-sans-serif, system-ui, sans-serif;
|
|
1086
|
-
font-size: .9rem;
|
|
1087
|
-
font-weight: 800;
|
|
1088
|
-
text-transform: uppercase;
|
|
1089
|
-
}
|
|
1090
|
-
.eyebrow::before {
|
|
1091
|
-
width: 44px;
|
|
1092
|
-
height: 2px;
|
|
1093
|
-
content: "";
|
|
1094
|
-
background: #df9a2f;
|
|
1095
|
-
}
|
|
1096
|
-
h1 {
|
|
1097
|
-
position: relative;
|
|
1098
|
-
z-index: 1;
|
|
1099
|
-
margin-top: 1rem;
|
|
1100
|
-
font-family: "Campmate Script", ui-serif, Georgia, serif;
|
|
1101
|
-
font-size: clamp(4.5rem, 16vw, 8rem);
|
|
1102
|
-
font-weight: 400;
|
|
1103
|
-
line-height: .82;
|
|
1104
|
-
}
|
|
1105
|
-
.lead,
|
|
1106
|
-
.message,
|
|
1107
|
-
.retry {
|
|
1108
|
-
position: relative;
|
|
1109
|
-
z-index: 1;
|
|
1110
|
-
max-width: 560px;
|
|
1111
|
-
color: rgba(255, 247, 225, .84);
|
|
1112
|
-
font-size: 1.08rem;
|
|
1113
|
-
line-height: 1.65;
|
|
1114
|
-
}
|
|
1115
|
-
.lead {
|
|
1116
|
-
margin-top: 1.25rem;
|
|
1117
|
-
color: #b8d9cf;
|
|
1118
|
-
font-family: "NPS 2026", "Switchback", ui-sans-serif, system-ui, sans-serif;
|
|
1119
|
-
font-size: 1.22rem;
|
|
1120
|
-
font-weight: 850;
|
|
1121
|
-
line-height: 1.3;
|
|
1122
|
-
text-transform: uppercase;
|
|
1123
|
-
}
|
|
1124
|
-
.message {
|
|
1125
|
-
margin-top: .75rem;
|
|
1126
|
-
}
|
|
1127
|
-
.retry {
|
|
1128
|
-
margin-top: 1.4rem;
|
|
1129
|
-
color: #aac47d;
|
|
1130
|
-
font-family: "Switchback", ui-sans-serif, system-ui, sans-serif;
|
|
1131
|
-
font-size: .95rem;
|
|
1132
|
-
font-weight: 800;
|
|
1133
|
-
text-transform: uppercase;
|
|
1134
|
-
}
|
|
1135
|
-
</style>
|
|
1136
|
-
</head>
|
|
1137
|
-
<body>
|
|
1138
|
-
<div class="container">
|
|
1139
|
-
<div class="eyebrow">${eyebrow}</div>
|
|
1140
|
-
<h1>${title}</h1>
|
|
1141
|
-
<p class="lead">${lead}</p>
|
|
1142
|
-
<p class="message">${message}</p>
|
|
1143
|
-
${payload.retry ? `<p class="retry">Estimated reopening: ${Math.ceil(payload.retry / 60)} minutes.</p>` : ""}
|
|
1144
|
-
</div>
|
|
1145
|
-
</body>
|
|
1146
|
-
</html>`;
|
|
1147
|
-
}
|
|
1148
|
-
function escapeHtml(value) {
|
|
1149
|
-
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1150
|
-
}
|
|
1151
|
-
function maintenanceResponse(payload) {
|
|
1152
|
-
return siteModeResponse(payload);
|
|
1153
|
-
}
|
|
1154
|
-
function siteModeResponse(payload) {
|
|
1155
|
-
const headers = {
|
|
1156
|
-
"Content-Type": "text/html; charset=utf-8"
|
|
1157
|
-
};
|
|
1158
|
-
if (payload.retry) {
|
|
1159
|
-
headers["Retry-After"] = String(payload.retry);
|
|
1160
|
-
}
|
|
1161
|
-
if (payload.redirect) {
|
|
1162
|
-
return new Response(null, {
|
|
1163
|
-
status: 302,
|
|
1164
|
-
headers: { Location: payload.redirect }
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
return new Response(maintenanceHtml(payload), {
|
|
1168
|
-
status: payload.status || (payload.mode === "coming-soon" ? 200 : 503),
|
|
1169
|
-
headers
|
|
1170
|
-
});
|
|
1171
|
-
}
|
|
1172
|
-
function bypassCookieValue(secret, mode = "maintenance") {
|
|
1173
|
-
return `${bypassCookieName(mode)}=${secret}; Path=/; HttpOnly; SameSite=Lax`;
|
|
1174
|
-
}
|
|
1175
|
-
var ALWAYS_ALLOWED_PATHS = new Set([
|
|
1176
|
-
"/coming-soon",
|
|
1177
|
-
"/api/email/subscribe",
|
|
1178
|
-
"/favicon.ico"
|
|
1179
|
-
]);
|
|
1180
|
-
var ALWAYS_ALLOWED_PREFIXES = [
|
|
1181
|
-
"/css/",
|
|
1182
|
-
"/js/",
|
|
1183
|
-
"/images/",
|
|
1184
|
-
"/fonts/",
|
|
1185
|
-
"/assets/",
|
|
1186
|
-
"/_modules/",
|
|
1187
|
-
"/@vite/",
|
|
1188
|
-
"/@fs/",
|
|
1189
|
-
"/__deps/"
|
|
1190
|
-
];
|
|
1191
|
-
function isAlwaysAllowed(path3) {
|
|
1192
|
-
if (ALWAYS_ALLOWED_PATHS.has(path3))
|
|
1193
|
-
return true;
|
|
1194
|
-
return ALWAYS_ALLOWED_PREFIXES.some((p2) => path3.startsWith(p2));
|
|
1195
|
-
}
|
|
1196
|
-
function parseCookieHeader(header) {
|
|
1197
|
-
const out = {};
|
|
1198
|
-
if (!header)
|
|
1199
|
-
return out;
|
|
1200
|
-
for (const part of header.split(";")) {
|
|
1201
|
-
const trimmed = part.trim();
|
|
1202
|
-
const eq = trimmed.indexOf("=");
|
|
1203
|
-
if (eq === -1)
|
|
1204
|
-
continue;
|
|
1205
|
-
const k = trimmed.slice(0, eq).trim();
|
|
1206
|
-
const v = trimmed.slice(eq + 1).trim();
|
|
1207
|
-
if (k)
|
|
1208
|
-
out[k] = v;
|
|
1209
|
-
}
|
|
1210
|
-
return out;
|
|
1211
|
-
}
|
|
1212
|
-
function clientIp(req) {
|
|
1213
|
-
const fwd = req.headers.get("x-forwarded-for");
|
|
1214
|
-
if (fwd)
|
|
1215
|
-
return fwd.split(",")[0]?.trim() ?? "127.0.0.1";
|
|
1216
|
-
const real = req.headers.get("x-real-ip");
|
|
1217
|
-
if (real)
|
|
1218
|
-
return real;
|
|
1219
|
-
return "127.0.0.1";
|
|
1220
|
-
}
|
|
1221
|
-
async function maintenanceGate(req) {
|
|
1222
|
-
const payload = await activeSiteModePayload();
|
|
1223
|
-
if (!payload)
|
|
1224
|
-
return null;
|
|
1225
|
-
const mode = payload.mode ?? "maintenance";
|
|
1226
|
-
const url = new URL(req.url);
|
|
1227
|
-
const path3 = url.pathname;
|
|
1228
|
-
if (isAlwaysAllowed(path3))
|
|
1229
|
-
return null;
|
|
1230
|
-
if (payload.secret && isSecretPath(path3, payload.secret)) {
|
|
1231
|
-
return new Response(null, {
|
|
1232
|
-
status: 302,
|
|
1233
|
-
headers: {
|
|
1234
|
-
Location: "/",
|
|
1235
|
-
"Set-Cookie": bypassCookieValue(payload.secret, mode)
|
|
1236
|
-
}
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
const cookies = parseCookieHeader(req.headers.get("cookie"));
|
|
1240
|
-
const hasCookie = !!payload.secret && hasValidBypassCookie(cookies, payload.secret, mode);
|
|
1241
|
-
const ipAllowed = isAllowedIp(clientIp(req), payload.allowed);
|
|
1242
|
-
if (hasCookie || ipAllowed)
|
|
1243
|
-
return null;
|
|
1244
|
-
return siteModeResponse(payload);
|
|
1245
|
-
}
|
|
1246
|
-
// src/proxy.ts
|
|
1247
|
-
var API_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
1248
|
-
function isApiBoundRequest(req, pathname) {
|
|
1249
|
-
return pathname.startsWith("/api/") || API_METHODS.has(req.method);
|
|
1250
|
-
}
|
|
1251
|
-
async function proxyToBackend(req, backendBase, stripPrefix) {
|
|
1252
|
-
const incoming = new URL(req.url);
|
|
1253
|
-
let pathname = incoming.pathname;
|
|
1254
|
-
if (stripPrefix && (pathname === stripPrefix || pathname.startsWith(`${stripPrefix}/`))) {
|
|
1255
|
-
pathname = pathname.slice(stripPrefix.length) || "/";
|
|
1256
|
-
}
|
|
1257
|
-
const target = `${backendBase}${pathname}${incoming.search}`;
|
|
1258
|
-
const fwd = new Headers(req.headers);
|
|
1259
|
-
fwd.delete("host");
|
|
1260
|
-
fwd.delete("content-length");
|
|
1261
|
-
fwd.set("x-forwarded-host", incoming.host);
|
|
1262
|
-
fwd.set("x-forwarded-proto", incoming.protocol.replace(":", ""));
|
|
1263
|
-
const body = req.method === "GET" || req.method === "HEAD" ? undefined : await req.arrayBuffer();
|
|
1264
|
-
const upstream = await fetch(target, {
|
|
1265
|
-
method: req.method,
|
|
1266
|
-
headers: fwd,
|
|
1267
|
-
body,
|
|
1268
|
-
redirect: "manual"
|
|
1269
|
-
});
|
|
1270
|
-
const out = new Headers(upstream.headers);
|
|
1271
|
-
out.delete("content-length");
|
|
1272
|
-
out.delete("content-encoding");
|
|
1273
|
-
return new Response(upstream.body, {
|
|
1274
|
-
status: upstream.status,
|
|
1275
|
-
statusText: upstream.statusText,
|
|
1276
|
-
headers: out
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
|
-
export {
|
|
1280
|
-
up,
|
|
1281
|
-
siteModeResponse,
|
|
1282
|
-
siteModePayload,
|
|
1283
|
-
siteModeFilePath,
|
|
1284
|
-
config as server,
|
|
1285
|
-
proxyToBackend,
|
|
1286
|
-
maintenanceResponse,
|
|
1287
|
-
maintenancePayload,
|
|
1288
|
-
maintenanceHtml,
|
|
1289
|
-
maintenanceGate,
|
|
1290
|
-
maintenanceFilePath,
|
|
1291
|
-
launch,
|
|
1292
|
-
isSecretPath,
|
|
1293
|
-
isDownForMaintenance,
|
|
1294
|
-
isComingSoon,
|
|
1295
|
-
isApiBoundRequest,
|
|
1296
|
-
isAllowedIp,
|
|
1297
|
-
injectGlobalAutoImports,
|
|
1298
|
-
initiateImports,
|
|
1299
|
-
hasValidBypassCookie,
|
|
1300
|
-
generateAutoImportFiles,
|
|
1301
|
-
down,
|
|
1302
|
-
comingSoonPayload,
|
|
1303
|
-
comingSoonFilePath,
|
|
1304
|
-
comingSoon,
|
|
1305
|
-
bypassCookieValue,
|
|
1306
|
-
bypassCookieName,
|
|
1307
|
-
activeSiteModePayload,
|
|
1308
|
-
Controller
|
|
1309
|
-
};
|
|
1
|
+
export { config as server } from "./config";
|
|
2
|
+
export * from "./controllers/base";
|
|
3
|
+
export * from "./imports";
|
|
4
|
+
export * from "./maintenance";
|
|
5
|
+
export * from "./proxy";
|