feat: add logto auth and backend metrics integration

This commit is contained in:
2026-04-22 15:52:12 +08:00
parent b1bb28f5aa
commit c7ae2fbfcb
38 changed files with 4886 additions and 34 deletions
+43
View File
@@ -2,6 +2,11 @@ import {
createMarketController,
type CreateMarketControllerOptions
} from "./market/index";
import { renderMarketAuthGate } from "./market/auth-gate";
import {
isAuthResponseMessage,
type AuthStateValue
} from "../shared/auth-messages";
interface ChromeRuntimeLike {
getURL?: (path: string) => string;
@@ -16,6 +21,7 @@ interface BootContentScriptOptions {
options: CreateMarketControllerOptions
) => { dispose?: () => void; ready: Promise<void> };
document?: Document;
sendAuthMessage?: (message: unknown) => Promise<unknown>;
window?: Window;
}
@@ -26,11 +32,21 @@ export async function bootContentScript(
const currentDocument = options.document ?? document;
const controllerFactory =
options.createMarketController ?? createMarketController;
const sendAuthMessage =
options.sendAuthMessage ?? createRuntimeMessageSender();
if (!isMarketPage(currentWindow.location.href)) {
return null;
}
const authState = await readAuthState(sendAuthMessage);
if (!authState?.isAuthenticated) {
renderMarketAuthGate(currentDocument, currentWindow);
return {
ready: Promise.resolve()
};
}
installMarketPageBridge(currentDocument);
return controllerFactory({
@@ -46,6 +62,17 @@ export async function bootContentScript(
});
}
async function readAuthState(
sendMessage: (message: unknown) => Promise<unknown>
): Promise<AuthStateValue | null> {
const response = await sendMessage({ type: "auth:get-state" });
if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:state") {
return null;
}
return response.value;
}
function isMarketPage(url: string): boolean {
const parsedUrl = new URL(url);
const isXingtuHost =
@@ -101,6 +128,22 @@ function requestCsvDownload(csv: string): boolean {
return true;
}
function createRuntimeMessageSender(): (message: unknown) => Promise<unknown> {
return async (message: unknown) => {
const runtime = (
globalThis as typeof globalThis & {
chrome?: { runtime?: ChromeRuntimeLike };
}
).chrome?.runtime;
if (typeof runtime?.sendMessage !== "function") {
return null;
}
return runtime.sendMessage(message);
};
}
function downloadCsv(document: Document, window: Window, csv: string): void {
const blob = new Blob(["\uFEFF", csv], {
type: "text/csv;charset=utf-8"