@atria/server 0.0.9 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -10
- package/dist/auth/cookies.d.ts +11 -0
- package/dist/auth/cookies.js +38 -0
- package/dist/auth/cookies.js.map +1 -0
- package/dist/auth/hash.d.ts +2 -0
- package/dist/auth/hash.js +36 -0
- package/dist/auth/hash.js.map +1 -0
- package/dist/auth/oauth.d.ts +5 -0
- package/dist/auth/oauth.js +215 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/runtime.d.ts +28 -0
- package/dist/auth/runtime.js +528 -0
- package/dist/auth/runtime.js.map +1 -0
- package/dist/auth/store.d.ts +33 -0
- package/dist/auth/store.js +49 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/auth/types.d.ts +40 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/validation.d.ts +21 -0
- package/dist/auth/validation.js +97 -0
- package/dist/auth/validation.js.map +1 -0
- package/dist/dev/admin/assets.d.ts +2 -0
- package/dist/dev/admin/assets.js +30 -0
- package/dist/dev/admin/assets.js.map +1 -0
- package/dist/dev/admin/i18n.d.ts +2 -0
- package/dist/dev/admin/i18n.js +63 -0
- package/dist/dev/admin/i18n.js.map +1 -0
- package/dist/dev/admin/index.d.ts +3 -0
- package/dist/dev/admin/index.js +4 -0
- package/dist/dev/admin/index.js.map +1 -0
- package/dist/dev/admin/request.d.ts +14 -0
- package/dist/dev/admin/request.js +77 -0
- package/dist/dev/admin/request.js.map +1 -0
- package/dist/dev/admin/routing.d.ts +5 -0
- package/dist/dev/admin/routing.js +31 -0
- package/dist/dev/admin/routing.js.map +1 -0
- package/dist/dev/admin-assets.d.ts +2 -0
- package/dist/dev/admin-assets.js +30 -0
- package/dist/dev/admin-assets.js.map +1 -0
- package/dist/dev/admin.d.ts +2 -0
- package/dist/dev/admin.js +30 -0
- package/dist/dev/admin.js.map +1 -0
- package/dist/dev/constants.d.ts +11 -0
- package/dist/dev/constants.js +22 -0
- package/dist/dev/constants.js.map +1 -0
- package/dist/dev/health/index.d.ts +2 -0
- package/dist/dev/health/index.js +3 -0
- package/dist/dev/health/index.js.map +1 -0
- package/dist/dev/health/request.d.ts +14 -0
- package/dist/dev/health/request.js +22 -0
- package/dist/dev/health/request.js.map +1 -0
- package/dist/dev/health/state.d.ts +9 -0
- package/dist/dev/health/state.js +52 -0
- package/dist/dev/health/state.js.map +1 -0
- package/dist/dev/health.d.ts +9 -0
- package/dist/dev/health.js +52 -0
- package/dist/dev/health.js.map +1 -0
- package/dist/dev/http/errors.d.ts +2 -0
- package/dist/dev/http/errors.js +6 -0
- package/dist/dev/http/errors.js.map +1 -0
- package/dist/dev/http/routing.d.ts +3 -0
- package/dist/dev/http/routing.js +26 -0
- package/dist/dev/http/routing.js.map +1 -0
- package/dist/dev/i18n.d.ts +2 -0
- package/dist/dev/i18n.js +63 -0
- package/dist/dev/i18n.js.map +1 -0
- package/dist/dev/lifecycle.d.ts +2 -0
- package/dist/dev/lifecycle.js +10 -0
- package/dist/dev/lifecycle.js.map +1 -0
- package/dist/dev/public/index.d.ts +1 -0
- package/dist/dev/public/index.js +2 -0
- package/dist/dev/public/index.js.map +1 -0
- package/dist/dev/public/request.d.ts +9 -0
- package/dist/dev/public/request.js +29 -0
- package/dist/dev/public/request.js.map +1 -0
- package/dist/dev/public/responses.d.ts +3 -0
- package/dist/dev/public/responses.js +25 -0
- package/dist/dev/public/responses.js.map +1 -0
- package/dist/dev/public/routing.d.ts +1 -0
- package/dist/dev/public/routing.js +5 -0
- package/dist/dev/public/routing.js.map +1 -0
- package/dist/dev/responses.d.ts +2 -0
- package/dist/dev/responses.js +3 -0
- package/dist/dev/responses.js.map +1 -0
- package/dist/dev/routing.d.ts +3 -0
- package/dist/dev/routing.js +4 -0
- package/dist/dev/routing.js.map +1 -0
- package/dist/dev/setup/index.d.ts +2 -0
- package/dist/dev/setup/index.js +2 -0
- package/dist/dev/setup/index.js.map +1 -0
- package/dist/dev/setup/request.d.ts +5 -0
- package/dist/dev/setup/request.js +20 -0
- package/dist/dev/setup/request.js.map +1 -0
- package/dist/dev/setup/types.d.ts +5 -0
- package/dist/dev/setup/types.js +2 -0
- package/dist/dev/setup/types.js.map +1 -0
- package/dist/dev/static/files.d.ts +6 -0
- package/dist/dev/static/files.js +74 -0
- package/dist/dev/static/files.js.map +1 -0
- package/dist/dev/static/index.d.ts +4 -0
- package/dist/dev/static/index.js +5 -0
- package/dist/dev/static/index.js.map +1 -0
- package/dist/dev/static/paths.d.ts +1 -0
- package/dist/dev/static/paths.js +6 -0
- package/dist/dev/static/paths.js.map +1 -0
- package/dist/dev/static/publish.d.ts +1 -0
- package/dist/dev/static/publish.js +13 -0
- package/dist/dev/static/publish.js.map +1 -0
- package/dist/dev/static/resolver.d.ts +2 -0
- package/dist/dev/static/resolver.js +53 -0
- package/dist/dev/static/resolver.js.map +1 -0
- package/dist/dev/static/sender.d.ts +2 -0
- package/dist/dev/static/sender.js +11 -0
- package/dist/dev/static/sender.js.map +1 -0
- package/dist/dev/static-files.d.ts +6 -0
- package/dist/dev/static-files.js +74 -0
- package/dist/dev/static-files.js.map +1 -0
- package/dist/dev/types.d.ts +10 -0
- package/dist/dev/types.js +2 -0
- package/dist/dev/types.js.map +1 -0
- package/dist/server.js +65 -190
- package/dist/server.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type OAuthProviderId = "google" | "github";
|
|
2
|
+
export interface AuthUser {
|
|
3
|
+
id: string;
|
|
4
|
+
email: string | null;
|
|
5
|
+
name: string | null;
|
|
6
|
+
avatarUrl: string | null;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AuthIdentity {
|
|
11
|
+
provider: OAuthProviderId;
|
|
12
|
+
providerUserId: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
email: string | null;
|
|
15
|
+
name: string | null;
|
|
16
|
+
avatarUrl: string | null;
|
|
17
|
+
linkedAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AuthSession {
|
|
21
|
+
id: string;
|
|
22
|
+
userId: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
expiresAt: string;
|
|
25
|
+
}
|
|
26
|
+
export interface OAuthState {
|
|
27
|
+
id: string;
|
|
28
|
+
provider: OAuthProviderId;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
expiresAt: string;
|
|
31
|
+
redirectPath: string;
|
|
32
|
+
}
|
|
33
|
+
export interface OAuthProfile {
|
|
34
|
+
provider: OAuthProviderId;
|
|
35
|
+
providerUserId: string;
|
|
36
|
+
email: string | null;
|
|
37
|
+
emailVerified: boolean;
|
|
38
|
+
name: string | null;
|
|
39
|
+
avatarUrl: string | null;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface ValidationSuccess<T> {
|
|
2
|
+
ok: true;
|
|
3
|
+
value: T;
|
|
4
|
+
}
|
|
5
|
+
interface ValidationFailure {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: string;
|
|
8
|
+
}
|
|
9
|
+
type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
|
|
10
|
+
export interface RegisterCredentials {
|
|
11
|
+
email: string;
|
|
12
|
+
password: string;
|
|
13
|
+
name: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface LoginCredentials {
|
|
16
|
+
email: string;
|
|
17
|
+
password: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const validateRegisterCredentials: (payload: unknown) => ValidationResult<RegisterCredentials>;
|
|
20
|
+
export declare const validateLoginCredentials: (payload: unknown) => ValidationResult<LoginCredentials>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2
|
+
const MIN_PASSWORD_LENGTH = 8;
|
|
3
|
+
const MAX_PASSWORD_LENGTH = 256;
|
|
4
|
+
const MAX_NAME_LENGTH = 120;
|
|
5
|
+
const parseEmail = (value) => {
|
|
6
|
+
if (typeof value !== "string") {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const normalized = value.trim().toLowerCase();
|
|
10
|
+
if (!EMAIL_PATTERN.test(normalized)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return normalized;
|
|
14
|
+
};
|
|
15
|
+
const parsePassword = (value) => {
|
|
16
|
+
if (typeof value !== "string") {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const password = value.trim();
|
|
20
|
+
if (password.length < MIN_PASSWORD_LENGTH || password.length > MAX_PASSWORD_LENGTH) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return password;
|
|
24
|
+
};
|
|
25
|
+
const parseName = (value) => {
|
|
26
|
+
if (typeof value !== "string") {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (trimmed.length === 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return trimmed.slice(0, MAX_NAME_LENGTH);
|
|
34
|
+
};
|
|
35
|
+
const asRecord = (value) => typeof value === "object" && value !== null ? value : null;
|
|
36
|
+
export const validateRegisterCredentials = (payload) => {
|
|
37
|
+
const data = asRecord(payload);
|
|
38
|
+
if (!data) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
error: "Invalid request payload."
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const email = parseEmail(data.email);
|
|
45
|
+
if (!email) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
error: "A valid email is required."
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const password = parsePassword(data.password);
|
|
52
|
+
if (!password) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
error: "Password must have at least 8 characters."
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
ok: true,
|
|
60
|
+
value: {
|
|
61
|
+
email,
|
|
62
|
+
password,
|
|
63
|
+
name: parseName(data.name)
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
export const validateLoginCredentials = (payload) => {
|
|
68
|
+
const data = asRecord(payload);
|
|
69
|
+
if (!data) {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
error: "Invalid request payload."
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const email = parseEmail(data.email);
|
|
76
|
+
if (!email) {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: "A valid email is required."
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const password = parsePassword(data.password);
|
|
83
|
+
if (!password) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
error: "Password must have at least 8 characters."
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
ok: true,
|
|
91
|
+
value: {
|
|
92
|
+
email,
|
|
93
|
+
password
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/auth/validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { ADMIN_ASSET_PREFIX, LEGACY_ADMIN_ASSET_PREFIX } from "../constants.js";
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export const resolveAdminDistDir = () => {
|
|
6
|
+
try {
|
|
7
|
+
const adminEntryPath = require.resolve("@atria/admin/app.js");
|
|
8
|
+
return path.dirname(adminEntryPath);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
throw new Error("Admin assets are unavailable. Ensure @atria/admin is installed. (" + message + ")");
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export const resolveAdminAssetPath = (requestPath) => {
|
|
16
|
+
const matchedPrefix = requestPath.startsWith(ADMIN_ASSET_PREFIX)
|
|
17
|
+
? ADMIN_ASSET_PREFIX
|
|
18
|
+
: requestPath.startsWith(LEGACY_ADMIN_ASSET_PREFIX)
|
|
19
|
+
? LEGACY_ADMIN_ASSET_PREFIX
|
|
20
|
+
: null;
|
|
21
|
+
if (!matchedPrefix) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const relativePath = requestPath.slice(matchedPrefix.length);
|
|
25
|
+
if (relativePath.length === 0) {
|
|
26
|
+
return "/app.js";
|
|
27
|
+
}
|
|
28
|
+
return "/" + relativePath;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/dev/admin/assets.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC9C,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,mEAAmE,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC;IACvG,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,WAAmB,EAAiB,EAAE;IAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAC9D,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACjD,CAAC,CAAC,yBAAyB;YAC3B,CAAC,CAAC,IAAI,CAAC;IAEX,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,GAAG,YAAY,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { I18N_API_PREFIX, MIME_TYPES } from "../constants.js";
|
|
4
|
+
import { isInsideDirectory } from "../static/index.js";
|
|
5
|
+
const isValidLocaleId = (value) => /^[a-zA-Z0-9_-]+$/.test(value);
|
|
6
|
+
const listLocales = async (adminDistDir) => {
|
|
7
|
+
const localesDir = path.join(adminDistDir, "locales");
|
|
8
|
+
try {
|
|
9
|
+
const entries = await fs.readdir(localesDir, { withFileTypes: true });
|
|
10
|
+
return entries
|
|
11
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
12
|
+
.map((entry) => entry.name.replace(/\.json$/, ""))
|
|
13
|
+
.sort((left, right) => left.localeCompare(right));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export const handleI18nRequest = async (requestUrl, response, adminDistDir) => {
|
|
20
|
+
if (!requestUrl.pathname.startsWith(I18N_API_PREFIX)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const suffix = requestUrl.pathname.slice(I18N_API_PREFIX.length).replace(/^\/+/, "");
|
|
24
|
+
if (suffix.length === 0) {
|
|
25
|
+
const locales = await listLocales(adminDistDir);
|
|
26
|
+
response.writeHead(200, { "content-type": MIME_TYPES[".json"] });
|
|
27
|
+
response.end(JSON.stringify({
|
|
28
|
+
ok: true,
|
|
29
|
+
locales
|
|
30
|
+
}));
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const localeId = suffix.split("/")[0] ?? "";
|
|
34
|
+
if (!isValidLocaleId(localeId)) {
|
|
35
|
+
response.writeHead(400, { "content-type": MIME_TYPES[".json"] });
|
|
36
|
+
response.end(JSON.stringify({
|
|
37
|
+
ok: false,
|
|
38
|
+
error: "Invalid locale id."
|
|
39
|
+
}));
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const localesDir = path.join(adminDistDir, "locales");
|
|
43
|
+
const localeFilePath = path.join(localesDir, `${localeId}.json`);
|
|
44
|
+
if (!isInsideDirectory(localesDir, localeFilePath)) {
|
|
45
|
+
response.writeHead(403, { "content-type": MIME_TYPES[".txt"] });
|
|
46
|
+
response.end("Forbidden");
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const localeBuffer = await fs.readFile(localeFilePath);
|
|
51
|
+
response.writeHead(200, { "content-type": MIME_TYPES[".json"] });
|
|
52
|
+
response.end(localeBuffer);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
response.writeHead(404, { "content-type": MIME_TYPES[".json"] });
|
|
56
|
+
response.end(JSON.stringify({
|
|
57
|
+
ok: false,
|
|
58
|
+
error: "Locale not found."
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../../src/dev/admin/i18n.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dev/admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { AuthRuntime } from "../../auth/runtime.js";
|
|
3
|
+
import type { OwnerSetupState } from "../setup/types.js";
|
|
4
|
+
interface HandleAdminRequestOptions {
|
|
5
|
+
request: IncomingMessage;
|
|
6
|
+
response: ServerResponse;
|
|
7
|
+
requestUrl: URL;
|
|
8
|
+
runtimeDir: string;
|
|
9
|
+
adminDistDir: string;
|
|
10
|
+
ownerSetupState: OwnerSetupState;
|
|
11
|
+
authRuntime: AuthRuntime;
|
|
12
|
+
}
|
|
13
|
+
export declare const handleAdminRequest: (options: HandleAdminRequestOptions) => Promise<void>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { parseAuthMethod } from "@atria/shared";
|
|
2
|
+
import { MIME_TYPES } from "../constants.js";
|
|
3
|
+
import { buildAuthLocation, shouldRedirectAdminToAuth } from "./routing.js";
|
|
4
|
+
import { respondWithDefaultNotFound } from "../http/errors.js";
|
|
5
|
+
import { resolveRequestFile, sendFileResponse } from "../static/index.js";
|
|
6
|
+
import { resolveAdminAssetPath } from "./assets.js";
|
|
7
|
+
import { handleI18nRequest } from "./i18n.js";
|
|
8
|
+
const respondForbidden = (response) => {
|
|
9
|
+
response.writeHead(403, { "content-type": MIME_TYPES[".txt"] });
|
|
10
|
+
response.end("Forbidden");
|
|
11
|
+
};
|
|
12
|
+
export const handleAdminRequest = async (options) => {
|
|
13
|
+
const { request, response, requestUrl, runtimeDir, adminDistDir, ownerSetupState, authRuntime } = options;
|
|
14
|
+
const i18nHandled = await handleI18nRequest(requestUrl, response, adminDistDir);
|
|
15
|
+
if (i18nHandled) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const authHandled = await authRuntime.handleRequest(request, response, requestUrl);
|
|
19
|
+
if (authHandled) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const adminSession = await authRuntime.getSession(request);
|
|
23
|
+
const normalizedPath = requestUrl.pathname.replace(/\/+$/, "") || "/";
|
|
24
|
+
if (normalizedPath === "/setup" && !requestUrl.searchParams.get("broker_code")) {
|
|
25
|
+
const mode = ownerSetupState.pending ? "create" : "login";
|
|
26
|
+
const queryProvider = parseAuthMethod(requestUrl.searchParams.get("provider"));
|
|
27
|
+
const queryNext = requestUrl.searchParams.get("next");
|
|
28
|
+
const nextPath = queryNext && queryNext.startsWith("/") ? queryNext : undefined;
|
|
29
|
+
response.writeHead(302, {
|
|
30
|
+
location: buildAuthLocation(mode, queryProvider, nextPath)
|
|
31
|
+
});
|
|
32
|
+
response.end();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (shouldRedirectAdminToAuth(requestUrl.pathname)) {
|
|
36
|
+
if (ownerSetupState.pending) {
|
|
37
|
+
response.writeHead(302, {
|
|
38
|
+
location: buildAuthLocation("create", ownerSetupState.preferredAuthMethod)
|
|
39
|
+
});
|
|
40
|
+
response.end();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!adminSession.authenticated) {
|
|
44
|
+
const nextPath = requestUrl.pathname + requestUrl.search;
|
|
45
|
+
response.writeHead(302, {
|
|
46
|
+
location: buildAuthLocation("login", null, nextPath)
|
|
47
|
+
});
|
|
48
|
+
response.end();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const adminAssetPath = resolveAdminAssetPath(requestUrl.pathname);
|
|
53
|
+
if (adminAssetPath) {
|
|
54
|
+
const adminTarget = await resolveRequestFile(adminDistDir, decodeURIComponent(adminAssetPath), "strict");
|
|
55
|
+
if (adminTarget.type === "forbidden") {
|
|
56
|
+
respondForbidden(response);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (adminTarget.type === "not-found") {
|
|
60
|
+
respondWithDefaultNotFound(response);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
await sendFileResponse(response, adminTarget.filePath);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const targetFile = await resolveRequestFile(runtimeDir, decodeURIComponent(requestUrl.pathname), "spa-fallback");
|
|
67
|
+
if (targetFile.type === "forbidden") {
|
|
68
|
+
respondForbidden(response);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (targetFile.type === "not-found") {
|
|
72
|
+
respondWithDefaultNotFound(response);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
await sendFileResponse(response, targetFile.filePath);
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/dev/admin/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AuthMethod } from "@atria/shared";
|
|
2
|
+
type AuthRouteMode = "create" | "login";
|
|
3
|
+
export declare const buildAuthLocation: (mode: AuthRouteMode, preferredAuthMethod: AuthMethod | null, nextPath?: string) => string;
|
|
4
|
+
export declare const shouldRedirectAdminToAuth: (requestPath: string) => boolean;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export const buildAuthLocation = (mode, preferredAuthMethod, nextPath) => {
|
|
3
|
+
const pathName = mode === "create" ? "/create" : "/login";
|
|
4
|
+
const query = new URLSearchParams();
|
|
5
|
+
if (preferredAuthMethod) {
|
|
6
|
+
query.set("provider", preferredAuthMethod);
|
|
7
|
+
}
|
|
8
|
+
if (nextPath && nextPath.startsWith("/")) {
|
|
9
|
+
query.set("next", nextPath);
|
|
10
|
+
}
|
|
11
|
+
const queryString = query.toString();
|
|
12
|
+
return queryString.length > 0 ? pathName + "?" + queryString : pathName;
|
|
13
|
+
};
|
|
14
|
+
export const shouldRedirectAdminToAuth = (requestPath) => {
|
|
15
|
+
const normalizedPath = requestPath.replace(/\/+$/, "") || "/";
|
|
16
|
+
if (normalizedPath === "/setup" ||
|
|
17
|
+
normalizedPath === "/create" ||
|
|
18
|
+
normalizedPath === "/login" ||
|
|
19
|
+
normalizedPath === "/api/setup/status" ||
|
|
20
|
+
normalizedPath === "/api/health") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (normalizedPath === "/" || normalizedPath === "/index.html") {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (normalizedPath.startsWith("/api/")) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return path.extname(normalizedPath).length === 0;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../../../src/dev/admin/routing.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAmB,EACnB,mBAAsC,EACtC,QAAiB,EACT,EAAE;IACV,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IAEpC,IAAI,mBAAmB,EAAE,CAAC;QACxB,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACrC,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC1E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,WAAmB,EAAW,EAAE;IACxE,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;IAC9D,IACE,cAAc,KAAK,QAAQ;QAC3B,cAAc,KAAK,SAAS;QAC5B,cAAc,KAAK,QAAQ;QAC3B,cAAc,KAAK,mBAAmB;QACtC,cAAc,KAAK,aAAa,EAChC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,cAAc,KAAK,GAAG,IAAI,cAAc,KAAK,aAAa,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACnD,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { ADMIN_ASSET_PREFIX, LEGACY_ADMIN_ASSET_PREFIX } from "./constants.js";
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export const resolveAdminDistDir = () => {
|
|
6
|
+
try {
|
|
7
|
+
const adminEntryPath = require.resolve("@atria/admin/app.js");
|
|
8
|
+
return path.dirname(adminEntryPath);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
throw new Error("Admin assets are unavailable. Ensure @atria/admin is installed. (" + message + ")");
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export const resolveAdminAssetPath = (requestPath) => {
|
|
16
|
+
const matchedPrefix = requestPath.startsWith(ADMIN_ASSET_PREFIX)
|
|
17
|
+
? ADMIN_ASSET_PREFIX
|
|
18
|
+
: requestPath.startsWith(LEGACY_ADMIN_ASSET_PREFIX)
|
|
19
|
+
? LEGACY_ADMIN_ASSET_PREFIX
|
|
20
|
+
: null;
|
|
21
|
+
if (!matchedPrefix) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const relativePath = requestPath.slice(matchedPrefix.length);
|
|
25
|
+
if (relativePath.length === 0) {
|
|
26
|
+
return "/app.js";
|
|
27
|
+
}
|
|
28
|
+
return "/" + relativePath;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=admin-assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-assets.js","sourceRoot":"","sources":["../../src/dev/admin-assets.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC9C,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,mEAAmE,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC;IACvG,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,WAAmB,EAAiB,EAAE;IAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAC9D,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACjD,CAAC,CAAC,yBAAyB;YAC3B,CAAC,CAAC,IAAI,CAAC;IAEX,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,GAAG,YAAY,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { ADMIN_ASSET_PREFIX, LEGACY_ADMIN_ASSET_PREFIX } from "./constants.js";
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export const resolveAdminDistDir = () => {
|
|
6
|
+
try {
|
|
7
|
+
const adminEntryPath = require.resolve("@atria/admin/app.js");
|
|
8
|
+
return path.dirname(adminEntryPath);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
throw new Error("Admin assets are unavailable. Ensure @atria/admin is installed. (" + message + ")");
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export const resolveAdminAssetPath = (requestPath) => {
|
|
16
|
+
const matchedPrefix = requestPath.startsWith(ADMIN_ASSET_PREFIX)
|
|
17
|
+
? ADMIN_ASSET_PREFIX
|
|
18
|
+
: requestPath.startsWith(LEGACY_ADMIN_ASSET_PREFIX)
|
|
19
|
+
? LEGACY_ADMIN_ASSET_PREFIX
|
|
20
|
+
: null;
|
|
21
|
+
if (!matchedPrefix) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const relativePath = requestPath.slice(matchedPrefix.length);
|
|
25
|
+
if (relativePath.length === 0) {
|
|
26
|
+
return "/app.js";
|
|
27
|
+
}
|
|
28
|
+
return "/" + relativePath;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/dev/admin.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC9C,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,mEAAmE,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC;IACvG,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,WAAmB,EAAiB,EAAE;IAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAC9D,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACjD,CAAC,CAAC,yBAAyB;YAC3B,CAAC,CAAC,IAAI,CAAC;IAEX,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,GAAG,YAAY,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const DEV_PUBLIC_HOST = "localhost";
|
|
2
|
+
export declare const DEV_STUDIO_HOST = "studio.localhost";
|
|
3
|
+
export declare const ADMIN_ASSET_PREFIX = "/.atria/admin/";
|
|
4
|
+
export declare const LEGACY_ADMIN_ASSET_PREFIX = "/.atria/studio/";
|
|
5
|
+
export declare const I18N_API_PREFIX = "/api/admin/i18n";
|
|
6
|
+
export declare const MIME_TYPES: Record<string, string>;
|
|
7
|
+
export declare const DEFAULT_NOT_FOUND_TEXT = "404: The requested page was not found.";
|
|
8
|
+
export declare const DEFAULT_PUBLIC_UNAVAILABLE_TEXT = "503: Public site output is not published yet.";
|
|
9
|
+
export declare const ENABLE_LIVE_PUBLISH_TRANSITION = true;
|
|
10
|
+
export declare const PUBLIC_HOST_ALIASES: Set<string>;
|
|
11
|
+
export declare const STUDIO_HOST_ALIASES: Set<string>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const DEV_PUBLIC_HOST = "localhost";
|
|
2
|
+
export const DEV_STUDIO_HOST = "studio.localhost";
|
|
3
|
+
export const ADMIN_ASSET_PREFIX = "/.atria/admin/";
|
|
4
|
+
export const LEGACY_ADMIN_ASSET_PREFIX = "/.atria/studio/";
|
|
5
|
+
export const I18N_API_PREFIX = "/api/admin/i18n";
|
|
6
|
+
export const MIME_TYPES = {
|
|
7
|
+
".html": "text/html; charset=utf-8",
|
|
8
|
+
".js": "text/javascript; charset=utf-8",
|
|
9
|
+
".css": "text/css; charset=utf-8",
|
|
10
|
+
".json": "application/json; charset=utf-8",
|
|
11
|
+
".svg": "image/svg+xml",
|
|
12
|
+
".ico": "image/x-icon",
|
|
13
|
+
".txt": "text/plain; charset=utf-8",
|
|
14
|
+
".map": "application/json; charset=utf-8"
|
|
15
|
+
};
|
|
16
|
+
export const DEFAULT_NOT_FOUND_TEXT = "404: The requested page was not found.";
|
|
17
|
+
export const DEFAULT_PUBLIC_UNAVAILABLE_TEXT = "503: Public site output is not published yet.";
|
|
18
|
+
// Keep this switch isolated so LIVE unpublished<->published behavior is easy to remove later.
|
|
19
|
+
export const ENABLE_LIVE_PUBLISH_TRANSITION = true;
|
|
20
|
+
export const PUBLIC_HOST_ALIASES = new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
21
|
+
export const STUDIO_HOST_ALIASES = new Set(["studio.localhost"]);
|
|
22
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/dev/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAElD,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AACnD,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,yBAAyB;IACjC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,2BAA2B;IACnC,MAAM,EAAE,iCAAiC;CAC1C,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,wCAAwC,CAAC;AAC/E,MAAM,CAAC,MAAM,+BAA+B,GAAG,+CAA+C,CAAC;AAC/F,8FAA8F;AAC9F,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAEnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dev/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAA4B,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
import type { SiteTarget } from "../types.js";
|
|
3
|
+
import type { OwnerSetupState } from "../setup/types.js";
|
|
4
|
+
import type { DatabaseHealthState } from "./state.js";
|
|
5
|
+
interface HandleHealthRequestOptions {
|
|
6
|
+
response: ServerResponse;
|
|
7
|
+
siteTarget: SiteTarget;
|
|
8
|
+
publicOutputPublished: boolean;
|
|
9
|
+
ownerSetupState: OwnerSetupState;
|
|
10
|
+
databaseHealthState: DatabaseHealthState;
|
|
11
|
+
}
|
|
12
|
+
export declare const isHealthRequest: (requestUrl: URL) => boolean;
|
|
13
|
+
export declare const handleHealthRequest: (options: HandleHealthRequestOptions) => void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MIME_TYPES } from "../constants.js";
|
|
2
|
+
const HEALTH_PATH = "/api/health";
|
|
3
|
+
export const isHealthRequest = (requestUrl) => requestUrl.pathname === HEALTH_PATH;
|
|
4
|
+
export const handleHealthRequest = (options) => {
|
|
5
|
+
const { response, siteTarget, publicOutputPublished, ownerSetupState, databaseHealthState } = options;
|
|
6
|
+
response.writeHead(200, { "content-type": MIME_TYPES[".json"] });
|
|
7
|
+
response.end(JSON.stringify({
|
|
8
|
+
ok: databaseHealthState.reachable,
|
|
9
|
+
status: databaseHealthState.reachable ? "operational" : "degraded",
|
|
10
|
+
site: siteTarget,
|
|
11
|
+
publicOutputPublished,
|
|
12
|
+
ownerSetupPending: ownerSetupState.pending,
|
|
13
|
+
database: {
|
|
14
|
+
driver: databaseHealthState.driver,
|
|
15
|
+
source: databaseHealthState.source,
|
|
16
|
+
usesFallback: databaseHealthState.usesFallback,
|
|
17
|
+
reachable: databaseHealthState.reachable,
|
|
18
|
+
error: databaseHealthState.error
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/dev/health/request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK7C,MAAM,WAAW,GAAG,aAAa,CAAC;AAUlC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAe,EAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,WAAW,CAAC;AAEjG,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAmC,EAAQ,EAAE;IAC/E,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,qBAAqB,EAAE,eAAe,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAEtG,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjE,QAAQ,CAAC,GAAG,CACV,IAAI,CAAC,SAAS,CAAC;QACb,EAAE,EAAE,mBAAmB,CAAC,SAAS;QACjC,MAAM,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU;QAClE,IAAI,EAAE,UAAU;QAChB,qBAAqB;QACrB,iBAAiB,EAAE,eAAe,CAAC,OAAO;QAC1C,QAAQ,EAAE;YACR,MAAM,EAAE,mBAAmB,CAAC,MAAM;YAClC,MAAM,EAAE,mBAAmB,CAAC,MAAM;YAClC,YAAY,EAAE,mBAAmB,CAAC,YAAY;YAC9C,SAAS,EAAE,mBAAmB,CAAC,SAAS;YACxC,KAAK,EAAE,mBAAmB,CAAC,KAAK;SACjC;KACF,CAAC,CACH,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DatabaseDriver, type DatabaseSource } from "@atria/db";
|
|
2
|
+
export interface DatabaseHealthState {
|
|
3
|
+
driver: DatabaseDriver;
|
|
4
|
+
source: DatabaseSource;
|
|
5
|
+
usesFallback: boolean;
|
|
6
|
+
reachable: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare const readDatabaseHealthState: (projectRoot: string) => Promise<DatabaseHealthState>;
|