@wizzlethorpe/vaults 0.9.8 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -3
- package/dist/build.js +71 -5
- package/dist/build.js.map +1 -1
- package/dist/commands/oidc.js +242 -0
- package/dist/commands/oidc.js.map +1 -0
- package/dist/commands/preview.js +4 -0
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/push.js +3 -0
- package/dist/commands/push.js.map +1 -1
- package/dist/config.js +21 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -1
- package/dist/render/auth-template.js +201 -12
- package/dist/render/auth-template.js.map +1 -1
- package/dist/render/handlers/builtin/battlemap.js +30 -3
- package/dist/render/handlers/builtin/battlemap.js.map +1 -1
- package/dist/render/layout.js +22 -11
- package/dist/render/layout.js.map +1 -1
- package/dist/render/oidc-match.js +30 -0
- package/dist/render/oidc-match.js.map +1 -0
- package/dist/render/pipeline.js +16 -1
- package/dist/render/pipeline.js.map +1 -1
- package/dist/render/preview.js +6 -0
- package/dist/render/preview.js.map +1 -1
- package/dist/render/styles.js +3 -1
- package/dist/render/styles.js.map +1 -1
- package/dist/settings.js +6 -1
- package/dist/settings.js.map +1 -1
- package/package.json +4 -1
|
@@ -6,15 +6,18 @@ export function renderAuthMiddleware(cfg) {
|
|
|
6
6
|
const rolesLiteral = JSON.stringify(cfg.roles);
|
|
7
7
|
const passwordsLiteral = JSON.stringify(cfg.rolePasswords);
|
|
8
8
|
const patreonLiteral = JSON.stringify(cfg.patreon ?? null);
|
|
9
|
+
const oidcLiteral = JSON.stringify(cfg.oidc ?? null);
|
|
9
10
|
return `// Auto-generated by the vaults CLI. Do not edit by hand.
|
|
10
11
|
// Roles, password hashes, and routing live here so the deployed Function
|
|
11
12
|
// is fully self-contained and doesn't need any other binding besides
|
|
12
13
|
// SESSION_SECRET (set via wrangler secret). When Patreon is configured,
|
|
13
|
-
// PATREON_CLIENT_SECRET also has to be set as a Wrangler secret
|
|
14
|
+
// PATREON_CLIENT_SECRET also has to be set as a Wrangler secret; when
|
|
15
|
+
// OIDC is configured, OAUTH_CLIENT_SECRET likewise.
|
|
14
16
|
|
|
15
17
|
const ROLES = ${rolesLiteral};
|
|
16
18
|
const PASSWORDS = ${passwordsLiteral};
|
|
17
19
|
const PATREON = ${patreonLiteral};
|
|
20
|
+
const OIDC = ${oidcLiteral};
|
|
18
21
|
const COOKIE_NAME = "vault_role";
|
|
19
22
|
// Non-HttpOnly companion cookie carrying the role name only; the auth check
|
|
20
23
|
// uses COOKIE_NAME (which is signed and HttpOnly), this one is purely for UI.
|
|
@@ -97,6 +100,17 @@ export const onRequest = async (ctx) => {
|
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
// /auth/oidc/* — only mounted when the build saw an OIDC config with at
|
|
104
|
+
// least one role rule. Same session-cookie contract as password login.
|
|
105
|
+
if (OIDC) {
|
|
106
|
+
if (url.pathname === "/auth/oidc/start" && request.method === "GET") {
|
|
107
|
+
return handleOidcStart(request, env);
|
|
108
|
+
}
|
|
109
|
+
if (url.pathname === "/auth/oidc/callback" && request.method === "GET") {
|
|
110
|
+
return handleOidcCallback(request, env);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
// /_batch; bulk source fetch for sync clients (Foundry). Body is
|
|
101
115
|
// newline-separated paths under text/plain so the request stays CORS-
|
|
102
116
|
// simple (no preflight per file → no OPTIONS rate-limit). Response is
|
|
@@ -500,8 +514,11 @@ function escAttr(s) { return String(s).replace(/[&<>"]/g, (c) => ({ "&": "&"
|
|
|
500
514
|
// /login with an error param on failure. CSRF state rides through a short-
|
|
501
515
|
// lived signed cookie so the callback can verify the round-trip.
|
|
502
516
|
|
|
503
|
-
|
|
504
|
-
|
|
517
|
+
// Shared by the Patreon and OIDC flows; only one OAuth round-trip can be in
|
|
518
|
+
// flight per browser at a time, and the state UUID check keeps a callback
|
|
519
|
+
// from one flow from completing the other's.
|
|
520
|
+
const STATE_COOKIE = "vault_oauth_state";
|
|
521
|
+
const STATE_TTL = 600; // 10 minutes — long enough for the user to authorise
|
|
505
522
|
|
|
506
523
|
async function handlePatreonStart(request, env) {
|
|
507
524
|
if (!env.PATREON_CLIENT_SECRET) {
|
|
@@ -538,7 +555,7 @@ async function handlePatreonCallback(request, env) {
|
|
|
538
555
|
|
|
539
556
|
const stateData = await readStateCookie(request, env.SESSION_SECRET);
|
|
540
557
|
// Always clear the state cookie regardless of outcome.
|
|
541
|
-
const clearState = clearCookieVariants(
|
|
558
|
+
const clearState = clearCookieVariants(STATE_COOKIE);
|
|
542
559
|
|
|
543
560
|
if (!stateData || stateData.state !== state) {
|
|
544
561
|
const headers = new Headers({ Location: "/login?error=patreon_state_mismatch" });
|
|
@@ -648,23 +665,168 @@ async function patreonFetchIdentity(accessToken) {
|
|
|
648
665
|
return await res.json();
|
|
649
666
|
}
|
|
650
667
|
|
|
651
|
-
//
|
|
652
|
-
//
|
|
653
|
-
//
|
|
668
|
+
// ── OIDC OAuth (optional, additive to password login) ────────────────────
|
|
669
|
+
// Bound only when OIDC !== null (i.e. the build saw an oidc block with at
|
|
670
|
+
// least one role rule). Standard authorization-code flow with PKCE (S256):
|
|
671
|
+
// the code_verifier rides in the signed state cookie, the challenge goes to
|
|
672
|
+
// the authorization endpoint. Identity comes from the userinfo endpoint;
|
|
673
|
+
// the visitor's email is matched against per-role email/domain rules.
|
|
674
|
+
|
|
675
|
+
async function handleOidcStart(request, env) {
|
|
676
|
+
if (!env.OAUTH_CLIENT_SECRET) {
|
|
677
|
+
return new Response("OIDC login is misconfigured: OAUTH_CLIENT_SECRET secret is missing.", { status: 500 });
|
|
678
|
+
}
|
|
679
|
+
const url = new URL(request.url);
|
|
680
|
+
const next = safeNext(url.searchParams.get("next"));
|
|
681
|
+
const stateValue = crypto.randomUUID();
|
|
682
|
+
const verifier = base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)));
|
|
683
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
684
|
+
const challenge = base64UrlEncode(new Uint8Array(digest));
|
|
685
|
+
const stateCookie = await signStateCookie({ state: stateValue, next, verifier }, env.SESSION_SECRET);
|
|
686
|
+
|
|
687
|
+
const authorize = new URL(OIDC.authorizationEndpoint);
|
|
688
|
+
authorize.searchParams.set("response_type", "code");
|
|
689
|
+
authorize.searchParams.set("client_id", OIDC.clientId);
|
|
690
|
+
authorize.searchParams.set("redirect_uri", url.origin + "/auth/oidc/callback");
|
|
691
|
+
authorize.searchParams.set("scope", "openid email");
|
|
692
|
+
authorize.searchParams.set("state", stateValue);
|
|
693
|
+
authorize.searchParams.set("code_challenge", challenge);
|
|
694
|
+
authorize.searchParams.set("code_challenge_method", "S256");
|
|
695
|
+
|
|
696
|
+
const headers = new Headers({ Location: authorize.toString() });
|
|
697
|
+
headers.append("Set-Cookie", stateCookie);
|
|
698
|
+
return new Response(null, { status: 302, headers });
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
async function handleOidcCallback(request, env) {
|
|
702
|
+
if (!env.OAUTH_CLIENT_SECRET) {
|
|
703
|
+
return loginRedirect("/", "oidc_misconfigured");
|
|
704
|
+
}
|
|
705
|
+
const url = new URL(request.url);
|
|
706
|
+
const code = url.searchParams.get("code");
|
|
707
|
+
const state = url.searchParams.get("state");
|
|
708
|
+
if (!code || !state) return loginRedirect("/", "oidc_failed");
|
|
709
|
+
|
|
710
|
+
const stateData = await readStateCookie(request, env.SESSION_SECRET);
|
|
711
|
+
// Always clear the state cookie regardless of outcome.
|
|
712
|
+
const clearState = clearCookieVariants(STATE_COOKIE);
|
|
713
|
+
|
|
714
|
+
if (!stateData || stateData.state !== state) {
|
|
715
|
+
const headers = new Headers({ Location: "/login?error=oidc_state_mismatch" });
|
|
716
|
+
for (const v of clearState) headers.append("Set-Cookie", v);
|
|
717
|
+
return new Response(null, { status: 302, headers });
|
|
718
|
+
}
|
|
719
|
+
const next = stateData.next || "/";
|
|
720
|
+
|
|
721
|
+
// Exchange code → access token; used once, immediately, for userinfo.
|
|
722
|
+
let access;
|
|
723
|
+
try {
|
|
724
|
+
access = await oidcExchangeCode(code, url.origin + "/auth/oidc/callback", env.OAUTH_CLIENT_SECRET, stateData.verifier);
|
|
725
|
+
} catch (err) {
|
|
726
|
+
console.warn("OIDC token exchange failed:", err);
|
|
727
|
+
const headers = new Headers({ Location: "/login?error=oidc_token_exchange" });
|
|
728
|
+
for (const v of clearState) headers.append("Set-Cookie", v);
|
|
729
|
+
return new Response(null, { status: 302, headers });
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
let email;
|
|
733
|
+
try { email = await oidcFetchEmail(access); }
|
|
734
|
+
catch (err) {
|
|
735
|
+
console.warn("OIDC userinfo fetch failed:", err);
|
|
736
|
+
const headers = new Headers({ Location: "/login?error=oidc_identity" });
|
|
737
|
+
for (const v of clearState) headers.append("Set-Cookie", v);
|
|
738
|
+
return new Response(null, { status: 302, headers });
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const role = matchOidcRole(email, OIDC.roleRules);
|
|
742
|
+
if (!role) {
|
|
743
|
+
// Authenticated, but no rule grants this email a role.
|
|
744
|
+
const headers = new Headers({ Location: "/login?error=oidc_no_role&next=" + encodeURIComponent(next) });
|
|
745
|
+
for (const v of clearState) headers.append("Set-Cookie", v);
|
|
746
|
+
return new Response(null, { status: 302, headers });
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const cookie = await signSessionCookie(role, env.SESSION_SECRET);
|
|
750
|
+
const headers = new Headers({ Location: next });
|
|
751
|
+
headers.append("Set-Cookie", cookie);
|
|
752
|
+
headers.append("Set-Cookie", DISPLAY_COOKIE_NAME + "=" + encodeURIComponent(role)
|
|
753
|
+
+ "; Path=/; Secure; SameSite=None; Partitioned; Max-Age=" + COOKIE_MAX_AGE);
|
|
754
|
+
for (const v of clearState) headers.append("Set-Cookie", v);
|
|
755
|
+
return new Response(null, { status: 302, headers });
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Duplicated from cli/src/render/oidc-match.ts — the worker can't import TS
|
|
759
|
+
// modules, so keep the two copies in sync. Matching is exact and case-
|
|
760
|
+
// insensitive; a domain rule matches only the exact domain after the last
|
|
761
|
+
// '@' (subdomains are not implied).
|
|
762
|
+
function matchOidcRole(email, roleRules) {
|
|
763
|
+
const at = email.lastIndexOf("@");
|
|
764
|
+
if (at < 0) return null;
|
|
765
|
+
const lower = email.toLowerCase();
|
|
766
|
+
const domain = lower.slice(at + 1);
|
|
767
|
+
for (let i = ROLES.length - 1; i >= 0; i--) {
|
|
768
|
+
const rule = roleRules[ROLES[i]];
|
|
769
|
+
if (!rule) continue;
|
|
770
|
+
if ((rule.emails || []).some((e) => e.toLowerCase() === lower)) return ROLES[i];
|
|
771
|
+
if (domain && (rule.domains || []).some((d) => d.toLowerCase() === domain)) return ROLES[i];
|
|
772
|
+
}
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
async function oidcExchangeCode(code, redirectUri, clientSecret, verifier) {
|
|
777
|
+
const body = new URLSearchParams({
|
|
778
|
+
grant_type: "authorization_code",
|
|
779
|
+
code,
|
|
780
|
+
client_id: OIDC.clientId,
|
|
781
|
+
client_secret: clientSecret,
|
|
782
|
+
redirect_uri: redirectUri,
|
|
783
|
+
code_verifier: verifier || "",
|
|
784
|
+
});
|
|
785
|
+
const res = await fetch(OIDC.tokenEndpoint, {
|
|
786
|
+
method: "POST",
|
|
787
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
788
|
+
body: body.toString(),
|
|
789
|
+
});
|
|
790
|
+
if (!res.ok) throw new Error("token exchange status " + res.status);
|
|
791
|
+
const data = await res.json();
|
|
792
|
+
if (!data.access_token) throw new Error("no access_token in response");
|
|
793
|
+
return data.access_token;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
async function oidcFetchEmail(accessToken) {
|
|
797
|
+
const res = await fetch(OIDC.userinfoEndpoint, {
|
|
798
|
+
headers: { Authorization: "Bearer " + accessToken },
|
|
799
|
+
});
|
|
800
|
+
if (!res.ok) throw new Error("userinfo status " + res.status);
|
|
801
|
+
const data = await res.json();
|
|
802
|
+
if (typeof data.email !== "string" || !data.email) throw new Error("userinfo returned no email");
|
|
803
|
+
return data.email;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function base64UrlEncode(bytes) {
|
|
807
|
+
let s = "";
|
|
808
|
+
for (const b of bytes) s += String.fromCharCode(b);
|
|
809
|
+
return btoa(s).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// State cookie: stores { state, next } (plus the PKCE verifier for OIDC)
|
|
813
|
+
// signed with SESSION_SECRET, used to verify the OAuth callback came from
|
|
814
|
+
// our /start handler and not a forgery. Shared by both OAuth flows.
|
|
815
|
+
// Lifetime is short (STATE_TTL); kept distinct from the long-lived
|
|
654
816
|
// session cookie so a stolen state cookie can't impersonate a session.
|
|
655
817
|
|
|
656
818
|
async function signStateCookie(payload, secret) {
|
|
657
|
-
const exp = Math.floor(Date.now() / 1000) +
|
|
819
|
+
const exp = Math.floor(Date.now() / 1000) + STATE_TTL;
|
|
658
820
|
const data = JSON.stringify({ ...payload, exp });
|
|
659
821
|
const sig = await hmac(data, secret);
|
|
660
822
|
const value = btoa(data) + "." + sig;
|
|
661
|
-
return
|
|
662
|
-
+ "; Path=/; Secure; SameSite=Lax; HttpOnly; Max-Age=" +
|
|
823
|
+
return STATE_COOKIE + "=" + value
|
|
824
|
+
+ "; Path=/; Secure; SameSite=Lax; HttpOnly; Max-Age=" + STATE_TTL;
|
|
663
825
|
}
|
|
664
826
|
|
|
665
827
|
async function readStateCookie(request, secret) {
|
|
666
828
|
const cookies = parseCookie(request.headers.get("Cookie") || "");
|
|
667
|
-
const raw = cookies[
|
|
829
|
+
const raw = cookies[STATE_COOKIE];
|
|
668
830
|
if (!raw) return null;
|
|
669
831
|
const dot = raw.lastIndexOf(".");
|
|
670
832
|
if (dot < 0) return null;
|
|
@@ -822,6 +984,7 @@ function isSharedAsset(pathname) {
|
|
|
822
984
|
// 404s for every visitor. Build code that places root-level files:
|
|
823
985
|
// - styles.css / user.css — build.ts (writeFile join(outputDir, ...))
|
|
824
986
|
// - _handlers.js / _handlers.css — build.ts (handler asset bundles, root)
|
|
987
|
+
// - katex/… — build.ts (copyKatexAssets; math vaults only)
|
|
825
988
|
// - _foundry/importer.js + version.json — build.ts (foundry-importer bundle)
|
|
826
989
|
// - login.html — build.ts (multi-role only)
|
|
827
990
|
// - favicon.ico — build.ts (buildFavicon)
|
|
@@ -837,6 +1000,7 @@ function isSharedAsset(pathname) {
|
|
|
837
1000
|
if (pathname === "/user.css") return true;
|
|
838
1001
|
if (pathname === "/_handlers.js") return true;
|
|
839
1002
|
if (pathname === "/_handlers.css") return true;
|
|
1003
|
+
if (pathname === "/katex/katex.min.css" || pathname.startsWith("/katex/fonts/")) return true;
|
|
840
1004
|
if (pathname === "/_foundry/importer.js") return true;
|
|
841
1005
|
if (pathname === "/_foundry/version.json") return true;
|
|
842
1006
|
if (pathname === "/login.html") return true;
|
|
@@ -888,10 +1052,17 @@ export const LOGIN_HTML = `<!doctype html>
|
|
|
888
1052
|
}
|
|
889
1053
|
.patreon-btn:hover { filter: brightness(1.05); }
|
|
890
1054
|
.patreon-hint { color: var(--muted); font-size: 0.78rem; margin-top: 0.6rem; text-align: center; }
|
|
1055
|
+
.oidc-btn {
|
|
1056
|
+
display: flex; align-items: center; justify-content: center;
|
|
1057
|
+
width: 100%; padding: 0.55rem 1rem; font: inherit; font-size: 0.95rem;
|
|
1058
|
+
background: var(--accent); color: var(--accent-fg); border: 0; border-radius: 4px;
|
|
1059
|
+
cursor: pointer; text-decoration: none;
|
|
1060
|
+
}
|
|
1061
|
+
.oidc-btn:hover { filter: brightness(1.05); }
|
|
891
1062
|
</style>
|
|
892
1063
|
</head>
|
|
893
1064
|
<body>
|
|
894
|
-
<div class="login-card"
|
|
1065
|
+
<div class="login-card"__PATREON_ROLES_ATTR____OIDC_ATTR__>
|
|
895
1066
|
<h1>Sign in</h1>
|
|
896
1067
|
<p id="err" class="login-error" hidden></p>
|
|
897
1068
|
<form method="POST" action="/login">
|
|
@@ -916,6 +1087,10 @@ export const LOGIN_HTML = `<!doctype html>
|
|
|
916
1087
|
selector above only matters for password sign-in.
|
|
917
1088
|
</p>
|
|
918
1089
|
</div>
|
|
1090
|
+
<div id="oidc-section" hidden>
|
|
1091
|
+
<div class="login-divider">or</div>
|
|
1092
|
+
<a id="oidc-btn" class="oidc-btn" href="#">Sign in</a>
|
|
1093
|
+
</div>
|
|
919
1094
|
</div>
|
|
920
1095
|
<script>
|
|
921
1096
|
const params = new URLSearchParams(location.search);
|
|
@@ -934,6 +1109,12 @@ export const LOGIN_HTML = `<!doctype html>
|
|
|
934
1109
|
patreon_no_tier: "Signed in to Patreon, but your current pledge doesn't grant any of the configured tiers.",
|
|
935
1110
|
patreon_misconfigured: "Patreon login is misconfigured for this deploy.",
|
|
936
1111
|
patreon_failed: "Patreon sign-in failed.",
|
|
1112
|
+
oidc_state_mismatch: "Sign-in expired or was tampered with. Please try again.",
|
|
1113
|
+
oidc_token_exchange: "Couldn't complete sign-in with the identity provider. Try again.",
|
|
1114
|
+
oidc_identity: "Signed in, but the identity provider didn't return an email address.",
|
|
1115
|
+
oidc_no_role: "Signed in, but your account isn't authorized for any role here.",
|
|
1116
|
+
oidc_misconfigured: "Single sign-on is misconfigured for this deploy.",
|
|
1117
|
+
oidc_failed: "Sign-in failed.",
|
|
937
1118
|
};
|
|
938
1119
|
el.textContent = messages[err] || "Sign-in failed.";
|
|
939
1120
|
el.hidden = false;
|
|
@@ -946,6 +1127,14 @@ export const LOGIN_HTML = `<!doctype html>
|
|
|
946
1127
|
section.hidden = false;
|
|
947
1128
|
document.getElementById("patreon-btn").href = "/auth/patreon/start?next=" + encodeURIComponent(next);
|
|
948
1129
|
}
|
|
1130
|
+
// Same pattern for OIDC: the build stamps data-oidc with the provider's
|
|
1131
|
+
// display name when configured with at least one role rule.
|
|
1132
|
+
if (card.dataset.oidc) {
|
|
1133
|
+
document.getElementById("oidc-section").hidden = false;
|
|
1134
|
+
const oidcBtn = document.getElementById("oidc-btn");
|
|
1135
|
+
oidcBtn.textContent = "Sign in with " + card.dataset.oidc;
|
|
1136
|
+
oidcBtn.href = "/auth/oidc/start?next=" + encodeURIComponent(next);
|
|
1137
|
+
}
|
|
949
1138
|
// Autofocus moved here so it picks the right field whether the password
|
|
950
1139
|
// form is visible or the user is going for the Patreon button.
|
|
951
1140
|
const pwd = document.getElementById("password");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-template.js","sourceRoot":"","sources":["../../src/render/auth-template.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,mEAAmE;
|
|
1
|
+
{"version":3,"file":"auth-template.js","sourceRoot":"","sources":["../../src/render/auth-template.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,mEAAmE;AAuCnE,MAAM,UAAU,oBAAoB,CAAC,GAAuB;IAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAErD,OAAO;;;;;;;gBAOO,YAAY;oBACR,gBAAgB;kBAClB,cAAc;eACjB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+9BzB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmIlB,CAAC"}
|
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
// The browser runtime (BATTLEMAP_RUNTIME below) ships as a built-in asset
|
|
23
23
|
// concatenated into _handlers.js; styles go into _handlers.css.
|
|
24
24
|
//
|
|
25
|
-
// Layer paths are vault-relative and resolve to the absolute served URL.
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// Layer paths are vault-relative and resolve to the absolute served URL. The
|
|
26
|
+
// build's per-variant asset scanner stages them via battlemapLayerPaths below,
|
|
27
|
+
// so a layer nothing else references (e.g. a web-only composited overlay)
|
|
28
|
+
// still ships with the deploy.
|
|
28
29
|
import yaml from "js-yaml";
|
|
29
30
|
import { htmlEscape } from "../../../escape.js";
|
|
30
31
|
import { registerBuiltinAssets } from "../assets.js";
|
|
@@ -35,6 +36,32 @@ function servedSrc(path) {
|
|
|
35
36
|
function errorBox(message) {
|
|
36
37
|
return { html: `<div class="vaults-bm-error">${htmlEscape(message)}</div>` };
|
|
37
38
|
}
|
|
39
|
+
// ```battlemap fenced blocks in raw markdown source.
|
|
40
|
+
const FENCE_RE = /^```battlemap[ \t]*\r?\n([\s\S]*?)^```/gm;
|
|
41
|
+
/** All layer image paths (vault-relative) named by ```battlemap blocks in a
|
|
42
|
+
* markdown source. Used by the build's asset scanner to stage layers into
|
|
43
|
+
* each variant; unparseable blocks contribute nothing. */
|
|
44
|
+
export function battlemapLayerPaths(source) {
|
|
45
|
+
const paths = [];
|
|
46
|
+
for (const match of source.matchAll(FENCE_RE)) {
|
|
47
|
+
let spec;
|
|
48
|
+
try {
|
|
49
|
+
spec = (yaml.load(match[1]) ?? {});
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const lv of Array.isArray(spec.levels) ? spec.levels : []) {
|
|
55
|
+
if (!Array.isArray(lv?.layers))
|
|
56
|
+
continue;
|
|
57
|
+
for (const p of lv.layers) {
|
|
58
|
+
if (typeof p === "string" && p.length > 0)
|
|
59
|
+
paths.push(p);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return paths;
|
|
64
|
+
}
|
|
38
65
|
export const battlemapHandler = {
|
|
39
66
|
codeBlock: "battlemap",
|
|
40
67
|
render(content) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"battlemap.js","sourceRoot":"","sources":["../../../../src/render/handlers/builtin/battlemap.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,EAAE;AACF,iBAAiB;AACjB,uFAAuF;AACvF,2FAA2F;AAC3F,0FAA0F;AAC1F,kFAAkF;AAClF,oEAAoE;AACpE,YAAY;AACZ,mBAAmB;AACnB,yDAAyD;AACzD,iEAAiE;AACjE,0BAA0B;AAC1B,gBAAgB;AAChB,iEAAiE;AACjE,wEAAwE;AACxE,QAAQ;AACR,EAAE;AACF,0EAA0E;AAC1E,gEAAgE;AAChE,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"battlemap.js","sourceRoot":"","sources":["../../../../src/render/handlers/builtin/battlemap.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,EAAE;AACF,iBAAiB;AACjB,uFAAuF;AACvF,2FAA2F;AAC3F,0FAA0F;AAC1F,kFAAkF;AAClF,oEAAoE;AACpE,YAAY;AACZ,mBAAmB;AACnB,yDAAyD;AACzD,iEAAiE;AACjE,0BAA0B;AAC1B,gBAAgB;AAChB,iEAAiE;AACjE,wEAAwE;AACxE,QAAQ;AACR,EAAE;AACF,0EAA0E;AAC1E,gEAAgE;AAChE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAC1E,+BAA+B;AAE/B,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAmBrD,mEAAmE;AACnE,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,OAAO,EAAE,IAAI,EAAE,gCAAgC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC/E,CAAC;AAED,qDAAqD;AACrD,MAAM,QAAQ,GAAG,0CAA0C,CAAC;AAE5D;;2DAE2D;AAC3D,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAY,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,MAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC/E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;gBAAE,SAAS;YACzC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,MAAmB,EAAE,CAAC;gBACvC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAqB;IAChD,SAAS,EAAE,WAAW;IACtB,MAAM,CAAC,OAAe;QACpB,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAY,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,QAAQ,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,MAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;aACpF,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACZ,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YACjD,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;gBAC/B,CAAC,CAAE,EAAE,CAAC,MAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC5F,CAAC,CAAC,EAAE;SACP,CAAC,CAAC;aACF,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAExC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC,kCAAkC,CAAC,CAAC;QAE7E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,IAAI,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3F,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM;YAAE,MAAM,GAAG,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEtE,MAAM,SAAS,GAAG,MAAM;aACrB,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CACb,wEAAwE,CAAC,GAAG;cAC1E,mBAAmB,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,EAAE,CAAC,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAC5G;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,KAAK,GACT,CAAC,IAAI,CAAC,CAAC,CAAC,qGAAqG,CAAC,CAAC,CAAC,EAAE,CAAC;cACjH,4GAA4G,CAAC;QAEjH,MAAM,KAAK,GAAG,MAAM;aACjB,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM;iBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACZ,aAAa,SAAS,CAAC,CAAC,CAAC,UAAU,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,mBAAmB,CACzF;iBACA,IAAI,CAAC,EAAE,CAAC,CAAC;YACZ,OAAO,6BAA6B,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC,GAAG;kBACrF,eAAe,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;QAC1D,CAAC,CAAC;aACD,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,+DAA+D,CAAC,CAAC,CAAC,EAAE,CAAC;QAE5F,MAAM,IAAI,GACR,gCAAgC,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;cAClE,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,kBAAkB,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;cAClD,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,kBAAkB,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;cAClD,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG;cAC1D,6BAA6B;cAC7B,gDAAgD,SAAS,QAAQ;cACjE,gCAAgC,KAAK,QAAQ;cAC7C,QAAQ;cACR,gCAAgC,KAAK,GAAG,OAAO,QAAQ;cACvD,QAAQ,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkGzB,CAAC;AAEF,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;CAexB,CAAC;AAEF,qBAAqB,CAAC,gBAAgB,EAAE;IACtC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,8BAA8B,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;IACjF,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;CACzE,CAAC,CAAC"}
|
package/dist/render/layout.js
CHANGED
|
@@ -28,7 +28,7 @@ export function renderLayout(input) {
|
|
|
28
28
|
<link rel="icon" href="/favicon.ico">
|
|
29
29
|
<link rel="stylesheet" href="/styles.css?v=${attr(input.assetVersion)}">
|
|
30
30
|
<link rel="stylesheet" href="/user.css?v=${attr(input.assetVersion)}">
|
|
31
|
-
${input.hasHandlerCss ? `<link rel="stylesheet" href="/_handlers.css?v=${attr(input.assetVersion)}">` : ""}${input.hasHandlerJs ? `\n<script src="/_handlers.js?v=${attr(input.assetVersion)}" defer></script>` : ""}
|
|
31
|
+
${input.hasMathCss ? `<link rel="stylesheet" href="/katex/katex.min.css?v=${attr(input.assetVersion)}">\n` : ""}${input.hasHandlerCss ? `<link rel="stylesheet" href="/_handlers.css?v=${attr(input.assetVersion)}">` : ""}${input.hasHandlerJs ? `\n<script src="/_handlers.js?v=${attr(input.assetVersion)}" defer></script>` : ""}
|
|
32
32
|
${renderSocialMeta(input)}
|
|
33
33
|
${THEME_BOOT_SCRIPT}
|
|
34
34
|
</head>
|
|
@@ -66,7 +66,7 @@ ${THEME_BOOT_SCRIPT}
|
|
|
66
66
|
</aside>
|
|
67
67
|
</div>
|
|
68
68
|
${EXPLORER_INIT_SCRIPT}
|
|
69
|
-
${input.previewMode === "none" ? "" : hoverPreviewScript(input.previewMode
|
|
69
|
+
${input.previewMode === "none" && input.previewModeMobile === "none" ? "" : hoverPreviewScript(input.previewMode, input.previewModeMobile)}
|
|
70
70
|
${TOC_SCRIPT}
|
|
71
71
|
${SEARCH_SCRIPT}
|
|
72
72
|
${LIGHTBOX_SCRIPT}
|
|
@@ -262,16 +262,22 @@ const EXPLORER_INIT_SCRIPT = `<script>
|
|
|
262
262
|
if (explorer) explorer.open = true;
|
|
263
263
|
})();
|
|
264
264
|
</script>`;
|
|
265
|
-
function hoverPreviewScript(
|
|
265
|
+
function hoverPreviewScript(desktop, mobile) {
|
|
266
266
|
return `<script>
|
|
267
267
|
(function () {
|
|
268
268
|
// Hovering an internal link shows a transient preview (pointer devices only)
|
|
269
|
-
// that fades when you move away. When PIN is on,
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
|
|
269
|
+
// that fades when you move away. When PIN is on, the preview carries a "Go to
|
|
270
|
+
// page" footer on hover so a reader can navigate in one click; clicking the
|
|
271
|
+
// link itself pins the preview open instead of navigating, and a pinned
|
|
272
|
+
// preview stays (with a close button) until you click elsewhere or press
|
|
273
|
+
// Escape. When off, clicks navigate normally and the preview is hover-only.
|
|
274
274
|
const HOVERABLE = window.matchMedia('(hover: hover)').matches;
|
|
275
|
+
// Preview behavior is chosen per device class: pointer devices use the desktop
|
|
276
|
+
// mode, touch devices (no hover) use the mobile mode. 'none' for this device
|
|
277
|
+
// registers nothing; on touch, 'normal' has no hover to trigger it either.
|
|
278
|
+
const MODE = HOVERABLE ? '${desktop}' : '${mobile}';
|
|
279
|
+
if (MODE === 'none') return;
|
|
280
|
+
const PIN = MODE === 'sticky';
|
|
275
281
|
const cache = new Map();
|
|
276
282
|
let popover = null, showTimer = null, hideTimer = null, activeLink = null, pinned = false;
|
|
277
283
|
const HOVER_DELAY = 220, HIDE_DELAY = 180;
|
|
@@ -280,6 +286,10 @@ function hoverPreviewScript(sticky) {
|
|
|
280
286
|
if (popover) return popover;
|
|
281
287
|
popover = document.createElement('div');
|
|
282
288
|
popover.className = 'wiki-preview';
|
|
289
|
+
// Sticky mode shows the "Go to page" footer on hover too (CSS keyed off
|
|
290
|
+
// .is-sticky), so a reader can navigate in one click instead of clicking to
|
|
291
|
+
// pin and then clicking the footer.
|
|
292
|
+
if (PIN) popover.classList.add('is-sticky');
|
|
283
293
|
popover.addEventListener('mouseenter', () => { if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; } });
|
|
284
294
|
popover.addEventListener('mouseleave', () => { if (!pinned) schedHide(); });
|
|
285
295
|
popover.addEventListener('click', (e) => {
|
|
@@ -324,9 +334,10 @@ function hoverPreviewScript(sticky) {
|
|
|
324
334
|
html += '<div class="wiki-preview-title">' + esc(data.title) + '</div>' +
|
|
325
335
|
'<div class="wiki-preview-body">' + (data.summary || '') + '</div>';
|
|
326
336
|
}
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
// shows
|
|
337
|
+
// The "Go to page" footer is always in the markup; CSS shows it on any
|
|
338
|
+
// sticky-mode popover (.is-sticky) and on a pinned one (.is-pinned). In
|
|
339
|
+
// normal mode a transient hover preview shows no footer (the link itself
|
|
340
|
+
// navigates on click).
|
|
330
341
|
html += '<a class="wiki-preview-goto" href="' + esc(href) + '">Go to page →</a>';
|
|
331
342
|
return html;
|
|
332
343
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/render/layout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,GAAG,EAAE,QAAQ,IAAI,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/render/layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Pure email-to-role matching logic for the OIDC login flow, extracted so
|
|
2
|
+
// tests can exercise it without spinning up a Pages Function. The shipped
|
|
3
|
+
// middleware in auth-template.ts duplicates this logic verbatim — it has to
|
|
4
|
+
// live there as plain JS since the worker can't import TS modules at
|
|
5
|
+
// runtime. Keep the two copies in sync (small enough that drift is easy to
|
|
6
|
+
// spot in review).
|
|
7
|
+
/**
|
|
8
|
+
* Return the highest-ranked role whose rule matches the email, or null.
|
|
9
|
+
* Roles are ordered low → high; iterate from highest so a visitor matching
|
|
10
|
+
* several rules gets the strongest role, mirroring the Patreon tier matcher.
|
|
11
|
+
*/
|
|
12
|
+
export function matchOidcRole(email, roleRules, roles) {
|
|
13
|
+
const at = email.lastIndexOf("@");
|
|
14
|
+
if (at < 0)
|
|
15
|
+
return null;
|
|
16
|
+
const lower = email.toLowerCase();
|
|
17
|
+
const domain = lower.slice(at + 1);
|
|
18
|
+
for (let i = roles.length - 1; i >= 0; i--) {
|
|
19
|
+
const role = roles[i];
|
|
20
|
+
const rule = roleRules[role];
|
|
21
|
+
if (!rule)
|
|
22
|
+
continue;
|
|
23
|
+
if ((rule.emails ?? []).some((e) => e.toLowerCase() === lower))
|
|
24
|
+
return role;
|
|
25
|
+
if (domain && (rule.domains ?? []).some((d) => d.toLowerCase() === domain))
|
|
26
|
+
return role;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=oidc-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-match.js","sourceRoot":"","sources":["../../src/render/oidc-match.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,0EAA0E;AAC1E,4EAA4E;AAC5E,qEAAqE;AACrE,2EAA2E;AAC3E,mBAAmB;AAgBnB;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAa,EACb,SAAuC,EACvC,KAAe;IAEf,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5E,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;IAC1F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/render/pipeline.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { unified } from "unified";
|
|
2
2
|
import remarkParse from "remark-parse";
|
|
3
3
|
import remarkGfm from "remark-gfm";
|
|
4
|
+
import remarkMath from "remark-math";
|
|
5
|
+
import rehypeKatex from "rehype-katex";
|
|
4
6
|
import remarkRehype from "remark-rehype";
|
|
5
7
|
import rehypeRaw from "rehype-raw";
|
|
6
8
|
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
|
|
@@ -73,6 +75,9 @@ export async function renderMarkdown(source, context, fallbackTitle, preParsed)
|
|
|
73
75
|
const file = await unified()
|
|
74
76
|
.use(remarkParse)
|
|
75
77
|
.use(remarkGfm)
|
|
78
|
+
// Obsidian-style math: $inline$ and $$display$$ become math nodes at
|
|
79
|
+
// parse time (so underscores etc. inside math never hit emphasis rules).
|
|
80
|
+
.use(remarkMath)
|
|
76
81
|
// Handlers run early so any markdown they emit is processed by the
|
|
77
82
|
// rest of the pipeline (wikilinks resolve, embeds inline, etc.).
|
|
78
83
|
// Empty registry (no built-ins, no user handlers) short-circuits to
|
|
@@ -102,11 +107,21 @@ export async function renderMarkdown(source, context, fallbackTitle, preParsed)
|
|
|
102
107
|
.use(rehypeRaw)
|
|
103
108
|
.use(rehypeSlug)
|
|
104
109
|
.use(rehypeSanitize, sanitizeSchema)
|
|
110
|
+
// KaTeX runs AFTER sanitize: math travels through it as a harmless
|
|
111
|
+
// <code class="language-math"> element, and the markup KaTeX expands it
|
|
112
|
+
// into (inline styles, MathML) would otherwise be stripped. Safe because
|
|
113
|
+
// KaTeX generates that markup itself from plain text.
|
|
114
|
+
.use(rehypeKatex)
|
|
105
115
|
.use(rehypeStringify)
|
|
106
116
|
.process(content);
|
|
107
117
|
const title = (typeof fm.title === "string" && fm.title)
|
|
108
118
|
|| extractH1(parsed.content)
|
|
109
119
|
|| fallbackTitle;
|
|
110
|
-
|
|
120
|
+
const html = String(file);
|
|
121
|
+
// Cheap detection so the build links katex.min.css only where needed. A
|
|
122
|
+
// literal 'class="katex' inside a code fence false-positives, which merely
|
|
123
|
+
// loads the stylesheet unnecessarily.
|
|
124
|
+
const hasMath = html.includes('class="katex');
|
|
125
|
+
return { html, title, frontmatter: fm, outlinks, warnings, hasMath };
|
|
111
126
|
}
|
|
112
127
|
//# sourceMappingURL=pipeline.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/render/pipeline.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/render/pipeline.ts"],"names":[],"mappings":"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"}
|