@agent-native/core 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/adapters/convex/adapter.d.ts +24 -0
- package/dist/adapters/convex/adapter.d.ts.map +1 -0
- package/dist/adapters/convex/adapter.js +125 -0
- package/dist/adapters/convex/adapter.js.map +1 -0
- package/dist/adapters/convex/index.d.ts +4 -0
- package/dist/adapters/convex/index.d.ts.map +1 -0
- package/dist/adapters/convex/index.js +3 -0
- package/dist/adapters/convex/index.js.map +1 -0
- package/dist/adapters/drizzle/adapter.d.ts +36 -0
- package/dist/adapters/drizzle/adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle/adapter.js +210 -0
- package/dist/adapters/drizzle/adapter.js.map +1 -0
- package/dist/adapters/drizzle/index.d.ts +3 -0
- package/dist/adapters/drizzle/index.d.ts.map +1 -0
- package/dist/adapters/drizzle/index.js +3 -0
- package/dist/adapters/drizzle/index.js.map +1 -0
- package/dist/adapters/drizzle/schema.d.ts +146 -0
- package/dist/adapters/drizzle/schema.d.ts.map +1 -0
- package/dist/adapters/drizzle/schema.js +20 -0
- package/dist/adapters/drizzle/schema.js.map +1 -0
- package/dist/adapters/firestore/adapter.d.ts +3 -2
- package/dist/adapters/firestore/adapter.d.ts.map +1 -1
- package/dist/adapters/firestore/adapter.js +23 -6
- package/dist/adapters/firestore/adapter.js.map +1 -1
- package/dist/adapters/supabase/adapter.d.ts +2 -1
- package/dist/adapters/supabase/adapter.d.ts.map +1 -1
- package/dist/adapters/supabase/adapter.js +4 -1
- package/dist/adapters/supabase/adapter.js.map +1 -1
- package/dist/adapters/sync/config.d.ts +22 -2
- package/dist/adapters/sync/config.d.ts.map +1 -1
- package/dist/adapters/sync/config.js +175 -16
- package/dist/adapters/sync/config.js.map +1 -1
- package/dist/adapters/sync/create-file-sync.d.ts +32 -0
- package/dist/adapters/sync/create-file-sync.d.ts.map +1 -0
- package/dist/adapters/sync/create-file-sync.js +218 -0
- package/dist/adapters/sync/create-file-sync.js.map +1 -0
- package/dist/adapters/sync/file-sync.d.ts +40 -6
- package/dist/adapters/sync/file-sync.d.ts.map +1 -1
- package/dist/adapters/sync/file-sync.js +442 -97
- package/dist/adapters/sync/file-sync.js.map +1 -1
- package/dist/adapters/sync/index.d.ts +3 -2
- package/dist/adapters/sync/index.d.ts.map +1 -1
- package/dist/adapters/sync/index.js +3 -1
- package/dist/adapters/sync/index.js.map +1 -1
- package/dist/adapters/sync/merge.js +3 -2
- package/dist/adapters/sync/merge.js.map +1 -1
- package/dist/adapters/sync/types.d.ts +36 -2
- package/dist/adapters/sync/types.d.ts.map +1 -1
- package/dist/adapters/sync/types.js +22 -1
- package/dist/adapters/sync/types.js.map +1 -1
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/production-agent.d.ts +16 -0
- package/dist/agent/production-agent.d.ts.map +1 -0
- package/dist/agent/production-agent.js +152 -0
- package/dist/agent/production-agent.js.map +1 -0
- package/dist/agent/types.d.ts +38 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +2 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +37 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/client/PoweredByBadge.d.ts +14 -0
- package/dist/client/PoweredByBadge.d.ts.map +1 -0
- package/dist/client/PoweredByBadge.js +60 -0
- package/dist/client/PoweredByBadge.js.map +1 -0
- package/dist/client/ProductionAgentPanel.d.ts +10 -0
- package/dist/client/ProductionAgentPanel.d.ts.map +1 -0
- package/dist/client/ProductionAgentPanel.js +121 -0
- package/dist/client/ProductionAgentPanel.js.map +1 -0
- package/dist/client/Turnstile.d.ts +35 -0
- package/dist/client/Turnstile.d.ts.map +1 -0
- package/dist/client/Turnstile.js +77 -0
- package/dist/client/Turnstile.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-file-sync-status.d.ts +21 -0
- package/dist/client/use-file-sync-status.d.ts.map +1 -0
- package/dist/client/use-file-sync-status.js +65 -0
- package/dist/client/use-file-sync-status.js.map +1 -0
- package/dist/client/use-session.d.ts +16 -0
- package/dist/client/use-session.d.ts.map +1 -0
- package/dist/client/use-session.js +49 -0
- package/dist/client/use-session.js.map +1 -0
- package/dist/client/useProductionAgent.d.ts +18 -0
- package/dist/client/useProductionAgent.d.ts.map +1 -0
- package/dist/client/useProductionAgent.js +135 -0
- package/dist/client/useProductionAgent.js.map +1 -0
- package/dist/db/index.d.ts +21 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +17 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +5 -0
- package/dist/router/index.js.map +1 -0
- package/dist/scripts/core-scripts.d.ts +10 -0
- package/dist/scripts/core-scripts.d.ts.map +1 -0
- package/dist/scripts/core-scripts.js +15 -0
- package/dist/scripts/core-scripts.js.map +1 -0
- package/dist/scripts/db/exec.d.ts +11 -0
- package/dist/scripts/db/exec.d.ts.map +1 -0
- package/dist/scripts/db/exec.js +86 -0
- package/dist/scripts/db/exec.js.map +1 -0
- package/dist/scripts/db/index.d.ts +2 -0
- package/dist/scripts/db/index.d.ts.map +1 -0
- package/dist/scripts/db/index.js +6 -0
- package/dist/scripts/db/index.js.map +1 -0
- package/dist/scripts/db/query.d.ts +10 -0
- package/dist/scripts/db/query.d.ts.map +1 -0
- package/dist/scripts/db/query.js +96 -0
- package/dist/scripts/db/query.js.map +1 -0
- package/dist/scripts/db/schema.d.ts +12 -0
- package/dist/scripts/db/schema.d.ts.map +1 -0
- package/dist/scripts/db/schema.js +112 -0
- package/dist/scripts/db/schema.js.map +1 -0
- package/dist/scripts/index.d.ts +4 -0
- package/dist/scripts/index.d.ts.map +1 -1
- package/dist/scripts/index.js +4 -0
- package/dist/scripts/index.js.map +1 -1
- package/dist/scripts/runner.d.ts +3 -0
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +53 -14
- package/dist/scripts/runner.js.map +1 -1
- package/dist/server/auth.d.ts +59 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +442 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/captcha.d.ts +12 -0
- package/dist/server/captcha.d.ts.map +1 -0
- package/dist/server/captcha.js +43 -0
- package/dist/server/captcha.js.map +1 -0
- package/dist/server/create-server.d.ts +13 -10
- package/dist/server/create-server.d.ts.map +1 -1
- package/dist/server/create-server.js +41 -27
- package/dist/server/create-server.js.map +1 -1
- package/dist/server/index.d.ts +5 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +6 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/missing-key.d.ts +9 -5
- package/dist/server/missing-key.d.ts.map +1 -1
- package/dist/server/missing-key.js +12 -7
- package/dist/server/missing-key.js.map +1 -1
- package/dist/server/sse.d.ts +12 -7
- package/dist/server/sse.d.ts.map +1 -1
- package/dist/server/sse.js +79 -15
- package/dist/server/sse.js.map +1 -1
- package/dist/vite/client.d.ts +28 -5
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +36 -15
- package/dist/vite/client.js.map +1 -1
- package/dist/vite/dev-api-server.d.ts +10 -0
- package/dist/vite/dev-api-server.d.ts.map +1 -0
- package/dist/vite/dev-api-server.js +148 -0
- package/dist/vite/dev-api-server.js.map +1 -0
- package/dist/vite/index.d.ts +2 -3
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +2 -3
- package/dist/vite/index.js.map +1 -1
- package/package.json +26 -17
- package/src/templates/default/AGENTS.md +148 -22
- package/src/templates/default/_gitignore +9 -5
- package/src/templates/default/client/entry.client.tsx +4 -0
- package/src/templates/default/client/entry.server.tsx +55 -0
- package/src/templates/default/client/root.tsx +82 -0
- package/src/templates/default/client/routes/_index.tsx +19 -0
- package/src/templates/default/client/routes.ts +4 -0
- package/src/templates/default/client/vite-env.d.ts +5 -0
- package/src/templates/default/package.json +5 -7
- package/src/templates/default/react-router.config.ts +6 -0
- package/src/templates/default/server/lib/watcher.ts +21 -0
- package/src/templates/default/server/plugins/auth.ts +5 -0
- package/src/templates/default/server/plugins/file-sync.ts +39 -0
- package/src/templates/default/server/routes/[...page].get.ts +12 -0
- package/src/templates/default/server/routes/api/events.get.ts +7 -0
- package/src/templates/default/server/routes/api/file-sync/status.get.ts +13 -0
- package/src/templates/default/server/routes/api/hello.get.ts +5 -0
- package/src/templates/default/tsconfig.json +9 -1
- package/src/templates/default/vite.config.ts +4 -1
- package/tsconfig.base.json +3 -1
- package/dist/adapters/neon/adapter.d.ts +0 -28
- package/dist/adapters/neon/adapter.d.ts.map +0 -1
- package/dist/adapters/neon/adapter.js +0 -135
- package/dist/adapters/neon/adapter.js.map +0 -1
- package/dist/adapters/neon/index.d.ts +0 -3
- package/dist/adapters/neon/index.d.ts.map +0 -1
- package/dist/adapters/neon/index.js +0 -3
- package/dist/adapters/neon/index.js.map +0 -1
- package/dist/server/production.d.ts +0 -18
- package/dist/server/production.d.ts.map +0 -1
- package/dist/server/production.js +0 -37
- package/dist/server/production.js.map +0 -1
- package/dist/vite/express-plugin.d.ts +0 -14
- package/dist/vite/express-plugin.d.ts.map +0 -1
- package/dist/vite/express-plugin.js +0 -53
- package/dist/vite/express-plugin.js.map +0 -1
- package/dist/vite/server.d.ts +0 -21
- package/dist/vite/server.d.ts.map +0 -1
- package/dist/vite/server.js +0 -68
- package/dist/vite/server.js.map +0 -1
- package/src/templates/default/index.html +0 -14
- package/src/templates/default/server/index.ts +0 -22
- package/src/templates/default/server/node-build.ts +0 -4
- package/src/templates/default/vite.config.server.ts +0 -3
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { defineEventHandler, readBody, getMethod, setResponseHeader, setResponseStatus, getCookie, setCookie, deleteCookie, } from "h3";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Constants
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const COOKIE_NAME = "an_session";
|
|
9
|
+
const DEFAULT_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
|
|
10
|
+
const DEFAULT_SESSIONS_PATH = "data/.sessions.json";
|
|
11
|
+
let sessions = new Map();
|
|
12
|
+
let sessionsFilePath = DEFAULT_SESSIONS_PATH;
|
|
13
|
+
let sessionMaxAge = DEFAULT_MAX_AGE;
|
|
14
|
+
function resolveSessionsPath(customPath) {
|
|
15
|
+
return path.resolve(process.cwd(), customPath ?? DEFAULT_SESSIONS_PATH);
|
|
16
|
+
}
|
|
17
|
+
function loadSessions() {
|
|
18
|
+
try {
|
|
19
|
+
const raw = fs.readFileSync(sessionsFilePath, "utf-8");
|
|
20
|
+
const entries = JSON.parse(raw);
|
|
21
|
+
sessions = new Map(entries.map((s) => [s.token, s]));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
sessions = new Map();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function saveSessions() {
|
|
28
|
+
const dir = path.dirname(sessionsFilePath);
|
|
29
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
30
|
+
const entries = Array.from(sessions.values());
|
|
31
|
+
fs.writeFileSync(sessionsFilePath, JSON.stringify(entries, null, 2));
|
|
32
|
+
}
|
|
33
|
+
function pruneExpiredSessions() {
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
let pruned = false;
|
|
36
|
+
for (const [token, session] of sessions) {
|
|
37
|
+
if (now - session.createdAt > sessionMaxAge * 1000) {
|
|
38
|
+
sessions.delete(token);
|
|
39
|
+
pruned = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (pruned)
|
|
43
|
+
saveSessions();
|
|
44
|
+
}
|
|
45
|
+
function addSession(token) {
|
|
46
|
+
sessions.set(token, { token, createdAt: Date.now() });
|
|
47
|
+
saveSessions();
|
|
48
|
+
}
|
|
49
|
+
function removeSession(token) {
|
|
50
|
+
sessions.delete(token);
|
|
51
|
+
saveSessions();
|
|
52
|
+
}
|
|
53
|
+
function hasSession(token) {
|
|
54
|
+
const session = sessions.get(token);
|
|
55
|
+
if (!session)
|
|
56
|
+
return false;
|
|
57
|
+
if (Date.now() - session.createdAt > sessionMaxAge * 1000) {
|
|
58
|
+
sessions.delete(token);
|
|
59
|
+
saveSessions();
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Token resolution — supports ACCESS_TOKEN (single) or ACCESS_TOKENS (multi)
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
function getAccessTokens() {
|
|
68
|
+
const single = process.env.ACCESS_TOKEN;
|
|
69
|
+
const multi = process.env.ACCESS_TOKENS;
|
|
70
|
+
const tokens = [];
|
|
71
|
+
if (single)
|
|
72
|
+
tokens.push(single);
|
|
73
|
+
if (multi) {
|
|
74
|
+
for (const t of multi.split(",")) {
|
|
75
|
+
const trimmed = t.trim();
|
|
76
|
+
if (trimmed && !tokens.includes(trimmed))
|
|
77
|
+
tokens.push(trimmed);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return tokens;
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Dev mode detection
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
function isDevMode() {
|
|
86
|
+
return process.env.NODE_ENV !== "production";
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// getSession — the auth contract
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
let customGetSession = null;
|
|
92
|
+
let authDisabledMode = false;
|
|
93
|
+
const DEV_SESSION = { email: "local@localhost" };
|
|
94
|
+
/**
|
|
95
|
+
* Get the current auth session for a request.
|
|
96
|
+
*
|
|
97
|
+
* - In dev mode: always returns { email: "local@localhost" }
|
|
98
|
+
* - In production with built-in auth: returns session if cookie is valid
|
|
99
|
+
* - With custom auth (BYOA): delegates to the custom getSession
|
|
100
|
+
*/
|
|
101
|
+
export async function getSession(event) {
|
|
102
|
+
if (isDevMode())
|
|
103
|
+
return DEV_SESSION;
|
|
104
|
+
if (authDisabledMode)
|
|
105
|
+
return DEV_SESSION;
|
|
106
|
+
if (customGetSession)
|
|
107
|
+
return customGetSession(event);
|
|
108
|
+
const cookie = getCookie(event, COOKIE_NAME);
|
|
109
|
+
if (cookie && hasSession(cookie)) {
|
|
110
|
+
return { email: "user", token: cookie };
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Constant-time token comparison
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
function safeTokenMatch(input, tokens) {
|
|
118
|
+
const inputBuf = Buffer.from(input);
|
|
119
|
+
for (const token of tokens) {
|
|
120
|
+
const tokenBuf = Buffer.from(token);
|
|
121
|
+
if (inputBuf.length === tokenBuf.length &&
|
|
122
|
+
crypto.timingSafeEqual(inputBuf, tokenBuf)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Login page HTML
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
const LOGIN_HTML = `<!DOCTYPE html>
|
|
132
|
+
<html lang="en">
|
|
133
|
+
<head>
|
|
134
|
+
<meta charset="UTF-8">
|
|
135
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
136
|
+
<title>Sign in</title>
|
|
137
|
+
<style>
|
|
138
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
139
|
+
body {
|
|
140
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
141
|
+
background: #0a0a0a;
|
|
142
|
+
color: #e5e5e5;
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
min-height: 100vh;
|
|
147
|
+
}
|
|
148
|
+
.card {
|
|
149
|
+
width: 100%;
|
|
150
|
+
max-width: 360px;
|
|
151
|
+
padding: 2rem;
|
|
152
|
+
background: #141414;
|
|
153
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
154
|
+
border-radius: 12px;
|
|
155
|
+
}
|
|
156
|
+
h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 1.5rem; color: #fff; }
|
|
157
|
+
label { display: block; font-size: 0.8125rem; color: #888; margin-bottom: 0.375rem; }
|
|
158
|
+
input {
|
|
159
|
+
width: 100%;
|
|
160
|
+
padding: 0.625rem 0.75rem;
|
|
161
|
+
background: #1e1e1e;
|
|
162
|
+
border: 1px solid rgba(255,255,255,0.12);
|
|
163
|
+
border-radius: 8px;
|
|
164
|
+
color: #e5e5e5;
|
|
165
|
+
font-size: 0.9375rem;
|
|
166
|
+
outline: none;
|
|
167
|
+
transition: border-color 0.15s;
|
|
168
|
+
}
|
|
169
|
+
input:focus { border-color: rgba(255,255,255,0.3); }
|
|
170
|
+
button {
|
|
171
|
+
width: 100%;
|
|
172
|
+
margin-top: 1rem;
|
|
173
|
+
padding: 0.625rem;
|
|
174
|
+
background: #fff;
|
|
175
|
+
color: #000;
|
|
176
|
+
border: none;
|
|
177
|
+
border-radius: 8px;
|
|
178
|
+
font-size: 0.9375rem;
|
|
179
|
+
font-weight: 500;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
transition: opacity 0.15s;
|
|
182
|
+
}
|
|
183
|
+
button:hover { opacity: 0.85; }
|
|
184
|
+
.error { margin-top: 0.75rem; font-size: 0.8125rem; color: #f87171; display: none; }
|
|
185
|
+
.error.show { display: block; }
|
|
186
|
+
</style>
|
|
187
|
+
</head>
|
|
188
|
+
<body>
|
|
189
|
+
<div class="card">
|
|
190
|
+
<h1>Sign in</h1>
|
|
191
|
+
<form id="form">
|
|
192
|
+
<label for="token">Access token</label>
|
|
193
|
+
<input id="token" type="password" autocomplete="current-password" autofocus placeholder="Enter access token" />
|
|
194
|
+
<button type="submit">Continue</button>
|
|
195
|
+
<p class="error" id="err">Invalid token. Please try again.</p>
|
|
196
|
+
</form>
|
|
197
|
+
</div>
|
|
198
|
+
<script>
|
|
199
|
+
document.getElementById('form').addEventListener('submit', async (e) => {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
const token = document.getElementById('token').value;
|
|
202
|
+
const res = await fetch('/api/auth/login', {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
headers: { 'Content-Type': 'application/json' },
|
|
205
|
+
body: JSON.stringify({ token }),
|
|
206
|
+
});
|
|
207
|
+
if (res.ok) {
|
|
208
|
+
window.location.reload();
|
|
209
|
+
} else {
|
|
210
|
+
document.getElementById('err').classList.add('show');
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
</script>
|
|
214
|
+
</body>
|
|
215
|
+
</html>`;
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
// mountAuthMiddleware — mounts login/logout/session routes + auth guard
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
/**
|
|
220
|
+
* Mount auth middleware + login/logout/session routes onto an H3 app.
|
|
221
|
+
*
|
|
222
|
+
* @deprecated Use `autoMountAuth(app, options?)` instead for automatic
|
|
223
|
+
* dev/prod behavior. This function is kept for backwards compatibility
|
|
224
|
+
* when you need explicit control over the access token.
|
|
225
|
+
*/
|
|
226
|
+
export function mountAuthMiddleware(app, accessToken) {
|
|
227
|
+
mountAuthRoutes(app, [accessToken]);
|
|
228
|
+
}
|
|
229
|
+
function isPublicPath(url, publicPaths) {
|
|
230
|
+
const p = url.split("?")[0];
|
|
231
|
+
return publicPaths.some((pp) => p === pp || p.startsWith(pp + "/"));
|
|
232
|
+
}
|
|
233
|
+
function mountAuthRoutes(app, accessTokens, publicPaths = []) {
|
|
234
|
+
// POST /api/auth/login
|
|
235
|
+
app.use("/api/auth/login", defineEventHandler(async (event) => {
|
|
236
|
+
if (getMethod(event) !== "POST") {
|
|
237
|
+
setResponseStatus(event, 405);
|
|
238
|
+
return { error: "Method not allowed" };
|
|
239
|
+
}
|
|
240
|
+
const body = await readBody(event);
|
|
241
|
+
if (!body?.token ||
|
|
242
|
+
typeof body.token !== "string" ||
|
|
243
|
+
!safeTokenMatch(body.token, accessTokens)) {
|
|
244
|
+
setResponseStatus(event, 401);
|
|
245
|
+
return { error: "Invalid token" };
|
|
246
|
+
}
|
|
247
|
+
const sessionToken = crypto.randomBytes(32).toString("hex");
|
|
248
|
+
addSession(sessionToken);
|
|
249
|
+
setCookie(event, COOKIE_NAME, sessionToken, {
|
|
250
|
+
httpOnly: true,
|
|
251
|
+
secure: true,
|
|
252
|
+
sameSite: "lax",
|
|
253
|
+
path: "/",
|
|
254
|
+
maxAge: sessionMaxAge,
|
|
255
|
+
});
|
|
256
|
+
return { ok: true };
|
|
257
|
+
}));
|
|
258
|
+
// POST /api/auth/logout
|
|
259
|
+
app.use("/api/auth/logout", defineEventHandler((event) => {
|
|
260
|
+
const cookie = getCookie(event, COOKIE_NAME);
|
|
261
|
+
if (cookie)
|
|
262
|
+
removeSession(cookie);
|
|
263
|
+
deleteCookie(event, COOKIE_NAME, { path: "/" });
|
|
264
|
+
return { ok: true };
|
|
265
|
+
}));
|
|
266
|
+
// GET /api/auth/session — client session check
|
|
267
|
+
app.use("/api/auth/session", defineEventHandler(async (event) => {
|
|
268
|
+
if (getMethod(event) !== "GET") {
|
|
269
|
+
setResponseStatus(event, 405);
|
|
270
|
+
return { error: "Method not allowed" };
|
|
271
|
+
}
|
|
272
|
+
const session = await getSession(event);
|
|
273
|
+
return session ?? { error: "Not authenticated" };
|
|
274
|
+
}));
|
|
275
|
+
// Auth guard — runs before all other handlers
|
|
276
|
+
app.use(defineEventHandler(async (event) => {
|
|
277
|
+
const url = event.node.req.url ?? "/";
|
|
278
|
+
const p = url.split("?")[0];
|
|
279
|
+
// Skip auth routes
|
|
280
|
+
if (p === "/api/auth/login" ||
|
|
281
|
+
p === "/api/auth/logout" ||
|
|
282
|
+
p === "/api/auth/session") {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
// Skip public paths
|
|
286
|
+
if (isPublicPath(url, publicPaths)) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// Use getSession() so BYOA custom auth is respected
|
|
290
|
+
const session = await getSession(event);
|
|
291
|
+
if (session) {
|
|
292
|
+
return; // Authenticated
|
|
293
|
+
}
|
|
294
|
+
// Unauthenticated
|
|
295
|
+
if (p.startsWith("/api/")) {
|
|
296
|
+
setResponseStatus(event, 401);
|
|
297
|
+
setResponseHeader(event, "Content-Type", "application/json");
|
|
298
|
+
event.node.res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
setResponseHeader(event, "Content-Type", "text/html");
|
|
302
|
+
event.node.res.end(LOGIN_HTML);
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
// autoMountAuth — the recommended entry point
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
/**
|
|
309
|
+
* Automatically configure auth based on the environment:
|
|
310
|
+
*
|
|
311
|
+
* - **Dev mode** (`NODE_ENV !== "production"`): Auth is skipped entirely.
|
|
312
|
+
* `getSession()` returns `{ email: "local@localhost" }` for all requests.
|
|
313
|
+
*
|
|
314
|
+
* - **Production with ACCESS_TOKEN/ACCESS_TOKENS set**: Auth middleware is
|
|
315
|
+
* mounted. Unauthenticated requests see a login page. One env var is all
|
|
316
|
+
* you need.
|
|
317
|
+
*
|
|
318
|
+
* - **Production without tokens and AUTH_DISABLED !== "true"**: Refuses to
|
|
319
|
+
* start. Logs a clear error explaining what to do.
|
|
320
|
+
*
|
|
321
|
+
* - **Production with AUTH_DISABLED=true**: Auth is skipped (for apps behind
|
|
322
|
+
* infrastructure-level auth like Cloudflare Access or a VPN).
|
|
323
|
+
*
|
|
324
|
+
* Returns true if auth was mounted, false if skipped.
|
|
325
|
+
*/
|
|
326
|
+
export function autoMountAuth(app, options = {}) {
|
|
327
|
+
// In Nitro 3.0 dev mode, the H3 app may not be available yet.
|
|
328
|
+
// In dev mode auth is bypassed anyway, so we can safely skip.
|
|
329
|
+
if (!app) {
|
|
330
|
+
if (isDevMode()) {
|
|
331
|
+
authDisabledMode = false;
|
|
332
|
+
customGetSession = null;
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
throw new Error("autoMountAuth: H3 app is required. In Nitro plugins, pass nitroApp.h3App.");
|
|
336
|
+
}
|
|
337
|
+
// Reset globals to avoid stale state from prior calls
|
|
338
|
+
customGetSession = null;
|
|
339
|
+
authDisabledMode = false;
|
|
340
|
+
sessionMaxAge = options.maxAge ?? DEFAULT_MAX_AGE;
|
|
341
|
+
sessionsFilePath = resolveSessionsPath(options.sessionsPath);
|
|
342
|
+
const publicPaths = options.publicPaths ?? [];
|
|
343
|
+
if (options.getSession) {
|
|
344
|
+
customGetSession = options.getSession;
|
|
345
|
+
}
|
|
346
|
+
// Dev mode — skip auth entirely
|
|
347
|
+
if (isDevMode()) {
|
|
348
|
+
// Mount a session endpoint that returns the dev stub
|
|
349
|
+
app.use("/api/auth/session", defineEventHandler(async (event) => {
|
|
350
|
+
if (getMethod(event) !== "GET") {
|
|
351
|
+
setResponseStatus(event, 405);
|
|
352
|
+
return { error: "Method not allowed" };
|
|
353
|
+
}
|
|
354
|
+
return DEV_SESSION;
|
|
355
|
+
}));
|
|
356
|
+
// Mount no-op login/logout so client code doesn't break
|
|
357
|
+
app.use("/api/auth/login", defineEventHandler(() => ({ ok: true })));
|
|
358
|
+
app.use("/api/auth/logout", defineEventHandler(() => ({ ok: true })));
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
// BYOA with custom getSession — skip token check, mount session/guard routes
|
|
362
|
+
if (customGetSession) {
|
|
363
|
+
// Mount session endpoint
|
|
364
|
+
app.use("/api/auth/session", defineEventHandler(async (event) => {
|
|
365
|
+
if (getMethod(event) !== "GET") {
|
|
366
|
+
setResponseStatus(event, 405);
|
|
367
|
+
return { error: "Method not allowed" };
|
|
368
|
+
}
|
|
369
|
+
const session = await getSession(event);
|
|
370
|
+
return session ?? { error: "Not authenticated" };
|
|
371
|
+
}));
|
|
372
|
+
app.use("/api/auth/login", defineEventHandler(() => ({ ok: true })));
|
|
373
|
+
app.use("/api/auth/logout", defineEventHandler(() => ({ ok: true })));
|
|
374
|
+
// Mount auth guard that delegates to custom getSession
|
|
375
|
+
app.use(defineEventHandler(async (event) => {
|
|
376
|
+
const url = event.node.req.url ?? "/";
|
|
377
|
+
const p = url.split("?")[0];
|
|
378
|
+
if (p === "/api/auth/login" ||
|
|
379
|
+
p === "/api/auth/logout" ||
|
|
380
|
+
p === "/api/auth/session") {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// Skip public paths
|
|
384
|
+
if (isPublicPath(url, publicPaths)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const session = await getSession(event);
|
|
388
|
+
if (session)
|
|
389
|
+
return;
|
|
390
|
+
if (p.startsWith("/api/")) {
|
|
391
|
+
setResponseStatus(event, 401);
|
|
392
|
+
setResponseHeader(event, "Content-Type", "application/json");
|
|
393
|
+
event.node.res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
setResponseHeader(event, "Content-Type", "text/html");
|
|
397
|
+
event.node.res.end(LOGIN_HTML);
|
|
398
|
+
}));
|
|
399
|
+
console.log("[agent-native] Auth enabled — custom getSession provider.");
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
// Production — check for tokens
|
|
403
|
+
const tokens = getAccessTokens();
|
|
404
|
+
if (tokens.length === 0) {
|
|
405
|
+
// No tokens set — check if auth is explicitly disabled
|
|
406
|
+
if (process.env.AUTH_DISABLED === "true") {
|
|
407
|
+
authDisabledMode = true;
|
|
408
|
+
console.warn("[agent-native] AUTH_DISABLED=true — running in production without auth. " +
|
|
409
|
+
"Ensure this app is behind infrastructure-level auth (Cloudflare Access, VPN, etc.).");
|
|
410
|
+
// Mount session endpoint — getSession() will return DEV_SESSION
|
|
411
|
+
app.use("/api/auth/session", defineEventHandler(async (event) => {
|
|
412
|
+
if (getMethod(event) !== "GET") {
|
|
413
|
+
setResponseStatus(event, 405);
|
|
414
|
+
return { error: "Method not allowed" };
|
|
415
|
+
}
|
|
416
|
+
return DEV_SESSION;
|
|
417
|
+
}));
|
|
418
|
+
app.use("/api/auth/login", defineEventHandler(() => ({ ok: true })));
|
|
419
|
+
app.use("/api/auth/logout", defineEventHandler(() => ({ ok: true })));
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
// Refuse to start without auth in production
|
|
423
|
+
const msg = "\n" +
|
|
424
|
+
"=".repeat(70) +
|
|
425
|
+
"\n" +
|
|
426
|
+
" ERROR: Running in production without authentication.\n\n" +
|
|
427
|
+
" Set ACCESS_TOKEN=<your-secret> to enable auth, or\n" +
|
|
428
|
+
" set AUTH_DISABLED=true if this app is behind infrastructure auth.\n\n" +
|
|
429
|
+
" For multi-user access: ACCESS_TOKENS=token1,token2,token3\n" +
|
|
430
|
+
"=".repeat(70) +
|
|
431
|
+
"\n";
|
|
432
|
+
console.error(msg);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
// Production with tokens — mount auth
|
|
436
|
+
loadSessions();
|
|
437
|
+
pruneExpiredSessions();
|
|
438
|
+
mountAuthRoutes(app, tokens, publicPaths);
|
|
439
|
+
console.log(`[agent-native] Auth enabled — ${tokens.length} access token(s) configured.`);
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CaptchaVerifyResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
errorCodes?: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Verify a Cloudflare Turnstile token server-side.
|
|
7
|
+
*
|
|
8
|
+
* - If no secret key is provided (param or env), returns success (captcha is opt-in).
|
|
9
|
+
* - In dev mode (NODE_ENV !== "production"), always returns success.
|
|
10
|
+
*/
|
|
11
|
+
export declare function verifyCaptcha(token: string, secretKey?: string): Promise<CaptchaVerifyResult>;
|
|
12
|
+
//# sourceMappingURL=captcha.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captcha.d.ts","sourceRoot":"","sources":["../../src/server/captcha.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAKD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC,CAyC9B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Cloudflare Turnstile — server-side verification
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
const TURNSTILE_VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
|
|
5
|
+
/**
|
|
6
|
+
* Verify a Cloudflare Turnstile token server-side.
|
|
7
|
+
*
|
|
8
|
+
* - If no secret key is provided (param or env), returns success (captcha is opt-in).
|
|
9
|
+
* - In dev mode (NODE_ENV !== "production"), always returns success.
|
|
10
|
+
*/
|
|
11
|
+
export async function verifyCaptcha(token, secretKey) {
|
|
12
|
+
// Dev mode — skip captcha
|
|
13
|
+
if (process.env.NODE_ENV !== "production") {
|
|
14
|
+
return { success: true };
|
|
15
|
+
}
|
|
16
|
+
const secret = secretKey ?? process.env.TURNSTILE_SECRET_KEY;
|
|
17
|
+
// No secret configured — captcha is opt-in, allow through
|
|
18
|
+
if (!secret) {
|
|
19
|
+
console.warn("[captcha] TURNSTILE_SECRET_KEY is not set — captcha verification is disabled. " +
|
|
20
|
+
"Set TURNSTILE_SECRET_KEY and VITE_TURNSTILE_SITE_KEY to enable bot protection.");
|
|
21
|
+
return { success: true };
|
|
22
|
+
}
|
|
23
|
+
// No token provided by client
|
|
24
|
+
if (!token) {
|
|
25
|
+
return { success: false, errorCodes: ["missing-input-response"] };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(TURNSTILE_VERIFY_URL, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
31
|
+
body: new URLSearchParams({ secret, response: token }),
|
|
32
|
+
});
|
|
33
|
+
const data = (await res.json());
|
|
34
|
+
return {
|
|
35
|
+
success: data.success,
|
|
36
|
+
errorCodes: data["error-codes"],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return { success: false, errorCodes: ["network-error"] };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=captcha.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captcha.js","sourceRoot":"","sources":["../../src/server/captcha.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kDAAkD;AAClD,8EAA8E;AAO9E,MAAM,oBAAoB,GACxB,2DAA2D,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAa,EACb,SAAkB;IAElB,0BAA0B;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAE7D,0DAA0D;IAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CACV,gFAAgF;YAC9E,gFAAgF,CACnF,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,wBAAwB,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE;YAC5C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;SACvD,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAG7B,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;SAChC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import cors from "cors";
|
|
1
|
+
import { createApp, createRouter } from "h3";
|
|
3
2
|
export interface EnvKeyConfig {
|
|
4
3
|
/** Environment variable name (e.g. "HUBSPOT_ACCESS_TOKEN") */
|
|
5
4
|
key: string;
|
|
@@ -9,9 +8,9 @@ export interface EnvKeyConfig {
|
|
|
9
8
|
required?: boolean;
|
|
10
9
|
}
|
|
11
10
|
export interface CreateServerOptions {
|
|
12
|
-
/** CORS options.
|
|
13
|
-
cors?:
|
|
14
|
-
/** JSON body parser limit.
|
|
11
|
+
/** CORS options. Ignored (H3 handles CORS via middleware). Default: enabled. */
|
|
12
|
+
cors?: Record<string, unknown> | false;
|
|
13
|
+
/** JSON body parser limit. Kept for API compatibility (H3 uses readBody). */
|
|
15
14
|
jsonLimit?: string;
|
|
16
15
|
/** Custom ping message. Default: reads PING_MESSAGE env var, falls back to "pong" */
|
|
17
16
|
pingMessage?: string;
|
|
@@ -20,13 +19,17 @@ export interface CreateServerOptions {
|
|
|
20
19
|
/** Env key configuration for the settings UI. Enables /api/env-status and /api/env-vars routes. */
|
|
21
20
|
envKeys?: EnvKeyConfig[];
|
|
22
21
|
}
|
|
22
|
+
export interface CreateServerResult {
|
|
23
|
+
app: ReturnType<typeof createApp>;
|
|
24
|
+
router: ReturnType<typeof createRouter>;
|
|
25
|
+
}
|
|
23
26
|
/**
|
|
24
|
-
* Create a pre-configured
|
|
25
|
-
* - CORS
|
|
26
|
-
* - JSON body parser (50mb limit)
|
|
27
|
-
* - URL-encoded body parser
|
|
27
|
+
* Create a pre-configured H3 app with standard agent-native setup:
|
|
28
|
+
* - CORS headers via middleware
|
|
28
29
|
* - /api/ping health check
|
|
29
30
|
* - /api/env-status and /api/env-vars (when envKeys is provided)
|
|
31
|
+
*
|
|
32
|
+
* Returns { app, router } — mount routes on `router`.
|
|
30
33
|
*/
|
|
31
|
-
export declare function createServer(options?: CreateServerOptions):
|
|
34
|
+
export declare function createServer(options?: CreateServerOptions): CreateServerResult;
|
|
32
35
|
//# sourceMappingURL=create-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../../src/server/create-server.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../../src/server/create-server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EAKb,MAAM,IAAI,CAAC;AAKZ,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IACvC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mGAAmG;IACnG,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAuED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;IAClC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CAqGpB"}
|