third-audience-mdx 1.0.7 → 1.0.8

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.
@@ -0,0 +1,28 @@
1
+ interface AdminRecord {
2
+ passwordHash: string;
3
+ isDefaultPassword: boolean;
4
+ createdAt: string;
5
+ lastLoginAt: string | null;
6
+ apiKey?: string;
7
+ }
8
+ declare function generateDefaultPassword(): string;
9
+ declare function hashPassword(password: string): string;
10
+ declare function loadAdmin(): AdminRecord | null;
11
+ declare function saveAdmin(record: AdminRecord): void;
12
+ declare const DEFAULT_PASSWORD = "Chang3M3Now!";
13
+ declare function initAdmin(): {
14
+ password: string;
15
+ apiKey: string;
16
+ isNew: boolean;
17
+ };
18
+ declare function verifyPassword(password: string): boolean;
19
+ declare function updatePassword(newPassword: string): void;
20
+ declare function recordLogin(): void;
21
+ declare function generateApiKey(): string;
22
+ declare function getApiKey(): string | null;
23
+ declare function rotateApiKey(): string;
24
+ declare function verifyApiKey(key: string): boolean;
25
+ declare function signSession(payload: string): string;
26
+ declare function verifySession(token: string): boolean;
27
+
28
+ export { type AdminRecord, DEFAULT_PASSWORD, generateApiKey, generateDefaultPassword, getApiKey, hashPassword, initAdmin, loadAdmin, recordLogin, rotateApiKey, saveAdmin, signSession, updatePassword, verifyApiKey, verifyPassword, verifySession };
@@ -0,0 +1,28 @@
1
+ interface AdminRecord {
2
+ passwordHash: string;
3
+ isDefaultPassword: boolean;
4
+ createdAt: string;
5
+ lastLoginAt: string | null;
6
+ apiKey?: string;
7
+ }
8
+ declare function generateDefaultPassword(): string;
9
+ declare function hashPassword(password: string): string;
10
+ declare function loadAdmin(): AdminRecord | null;
11
+ declare function saveAdmin(record: AdminRecord): void;
12
+ declare const DEFAULT_PASSWORD = "Chang3M3Now!";
13
+ declare function initAdmin(): {
14
+ password: string;
15
+ apiKey: string;
16
+ isNew: boolean;
17
+ };
18
+ declare function verifyPassword(password: string): boolean;
19
+ declare function updatePassword(newPassword: string): void;
20
+ declare function recordLogin(): void;
21
+ declare function generateApiKey(): string;
22
+ declare function getApiKey(): string | null;
23
+ declare function rotateApiKey(): string;
24
+ declare function verifyApiKey(key: string): boolean;
25
+ declare function signSession(payload: string): string;
26
+ declare function verifySession(token: string): boolean;
27
+
28
+ export { type AdminRecord, DEFAULT_PASSWORD, generateApiKey, generateDefaultPassword, getApiKey, hashPassword, initAdmin, loadAdmin, recordLogin, rotateApiKey, saveAdmin, signSession, updatePassword, verifyApiKey, verifyPassword, verifySession };
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/dashboard/admin-store.ts
31
+ var admin_store_exports = {};
32
+ __export(admin_store_exports, {
33
+ DEFAULT_PASSWORD: () => DEFAULT_PASSWORD,
34
+ generateApiKey: () => generateApiKey,
35
+ generateDefaultPassword: () => generateDefaultPassword,
36
+ getApiKey: () => getApiKey,
37
+ hashPassword: () => hashPassword,
38
+ initAdmin: () => initAdmin,
39
+ loadAdmin: () => loadAdmin,
40
+ recordLogin: () => recordLogin,
41
+ rotateApiKey: () => rotateApiKey,
42
+ saveAdmin: () => saveAdmin,
43
+ signSession: () => signSession,
44
+ updatePassword: () => updatePassword,
45
+ verifyApiKey: () => verifyApiKey,
46
+ verifyPassword: () => verifyPassword,
47
+ verifySession: () => verifySession
48
+ });
49
+ module.exports = __toCommonJS(admin_store_exports);
50
+ var import_fs = __toESM(require("fs"));
51
+ var import_path = __toESM(require("path"));
52
+ var import_crypto = __toESM(require("crypto"));
53
+ function adminFilePath() {
54
+ const dataDir = process.env.TA_DATA_DIR ?? "data";
55
+ return import_path.default.join(process.cwd(), dataDir, "ta-admin.json");
56
+ }
57
+ function generateDefaultPassword() {
58
+ return import_crypto.default.randomBytes(6).toString("hex");
59
+ }
60
+ function hashPassword(password) {
61
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt";
62
+ return import_crypto.default.createHash("sha256").update(secret + password).digest("hex");
63
+ }
64
+ function loadAdmin() {
65
+ const filePath = adminFilePath();
66
+ if (!import_fs.default.existsSync(filePath)) return null;
67
+ try {
68
+ return JSON.parse(import_fs.default.readFileSync(filePath, "utf-8"));
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+ function saveAdmin(record) {
74
+ const filePath = adminFilePath();
75
+ const dir = import_path.default.dirname(filePath);
76
+ if (!import_fs.default.existsSync(dir)) import_fs.default.mkdirSync(dir, { recursive: true });
77
+ import_fs.default.writeFileSync(filePath, JSON.stringify(record, null, 2), "utf-8");
78
+ }
79
+ var DEFAULT_PASSWORD = "Chang3M3Now!";
80
+ function initAdmin() {
81
+ const existing = loadAdmin();
82
+ if (existing) return { password: "", apiKey: "", isNew: false };
83
+ const apiKey = generateApiKey();
84
+ saveAdmin({
85
+ passwordHash: hashPassword(DEFAULT_PASSWORD),
86
+ isDefaultPassword: true,
87
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
88
+ lastLoginAt: null,
89
+ apiKey: encryptApiKey(apiKey)
90
+ });
91
+ return { password: DEFAULT_PASSWORD, apiKey, isNew: true };
92
+ }
93
+ function verifyPassword(password) {
94
+ const record = loadAdmin();
95
+ if (!record) return false;
96
+ return record.passwordHash === hashPassword(password);
97
+ }
98
+ function updatePassword(newPassword) {
99
+ const record = loadAdmin();
100
+ if (!record) return;
101
+ saveAdmin({
102
+ ...record,
103
+ passwordHash: hashPassword(newPassword),
104
+ isDefaultPassword: false
105
+ });
106
+ }
107
+ function recordLogin() {
108
+ const record = loadAdmin();
109
+ if (!record) return;
110
+ saveAdmin({ ...record, lastLoginAt: (/* @__PURE__ */ new Date()).toISOString() });
111
+ }
112
+ var CIPHER = "aes-256-gcm";
113
+ function getEncryptionKey() {
114
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-fallback-key-change-me";
115
+ return import_crypto.default.createHash("sha256").update(secret).digest();
116
+ }
117
+ function encryptApiKey(plaintext) {
118
+ const iv = import_crypto.default.randomBytes(12);
119
+ const key = getEncryptionKey();
120
+ const cipher = import_crypto.default.createCipheriv(CIPHER, key, iv);
121
+ const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
122
+ const tag = cipher.getAuthTag();
123
+ return iv.toString("hex") + tag.toString("hex") + encrypted.toString("hex");
124
+ }
125
+ function decryptApiKey(encoded) {
126
+ try {
127
+ const iv = Buffer.from(encoded.slice(0, 24), "hex");
128
+ const tag = Buffer.from(encoded.slice(24, 56), "hex");
129
+ const encrypted = Buffer.from(encoded.slice(56), "hex");
130
+ const key = getEncryptionKey();
131
+ const decipher = import_crypto.default.createDecipheriv(CIPHER, key, iv);
132
+ decipher.setAuthTag(tag);
133
+ return decipher.update(encrypted) + decipher.final("utf8");
134
+ } catch {
135
+ return null;
136
+ }
137
+ }
138
+ function generateApiKey() {
139
+ return "ta_" + import_crypto.default.randomBytes(24).toString("hex");
140
+ }
141
+ function getApiKey() {
142
+ const record = loadAdmin();
143
+ if (!record?.apiKey) return null;
144
+ return decryptApiKey(record.apiKey);
145
+ }
146
+ function rotateApiKey() {
147
+ const record = loadAdmin();
148
+ if (!record) throw new Error("Admin store not initialised");
149
+ const newKey = generateApiKey();
150
+ saveAdmin({ ...record, apiKey: encryptApiKey(newKey) });
151
+ return newKey;
152
+ }
153
+ function verifyApiKey(key) {
154
+ const stored = getApiKey();
155
+ if (!stored) return false;
156
+ if (key.length !== stored.length) return false;
157
+ return import_crypto.default.timingSafeEqual(Buffer.from(key), Buffer.from(stored));
158
+ }
159
+ function signSession(payload) {
160
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt";
161
+ const sig = import_crypto.default.createHmac("sha256", secret).update(payload).digest("hex");
162
+ return `${payload}.${sig}`;
163
+ }
164
+ function verifySession(token) {
165
+ const lastDot = token.lastIndexOf(".");
166
+ if (lastDot === -1) return false;
167
+ const payload = token.slice(0, lastDot);
168
+ const sig = token.slice(lastDot + 1);
169
+ const expected = import_crypto.default.createHmac("sha256", process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt").update(payload).digest("hex");
170
+ if (sig.length !== expected.length) return false;
171
+ return import_crypto.default.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"));
172
+ }
173
+ // Annotate the CommonJS export names for ESM import in node:
174
+ 0 && (module.exports = {
175
+ DEFAULT_PASSWORD,
176
+ generateApiKey,
177
+ generateDefaultPassword,
178
+ getApiKey,
179
+ hashPassword,
180
+ initAdmin,
181
+ loadAdmin,
182
+ recordLogin,
183
+ rotateApiKey,
184
+ saveAdmin,
185
+ signSession,
186
+ updatePassword,
187
+ verifyApiKey,
188
+ verifyPassword,
189
+ verifySession
190
+ });
191
+ //# sourceMappingURL=admin-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dashboard/admin-store.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport crypto from 'crypto'\n\nexport interface AdminRecord {\n passwordHash: string // sha256(secret + password)\n isDefaultPassword: boolean\n createdAt: string\n lastLoginAt: string | null\n apiKey?: string // AES-256-GCM encrypted, for headless/external API callers\n}\n\nfunction adminFilePath(): string {\n const dataDir = process.env.TA_DATA_DIR ?? 'data'\n return path.join(process.cwd(), dataDir, 'ta-admin.json')\n}\n\nexport function generateDefaultPassword(): string {\n return crypto.randomBytes(6).toString('hex') // 12-char hex, easy to type\n}\n\nexport function hashPassword(password: string): string {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt'\n return crypto.createHash('sha256').update(secret + password).digest('hex')\n}\n\nexport function loadAdmin(): AdminRecord | null {\n const filePath = adminFilePath()\n if (!fs.existsSync(filePath)) return null\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8')) as AdminRecord\n } catch {\n return null\n }\n}\n\nexport function saveAdmin(record: AdminRecord): void {\n const filePath = adminFilePath()\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(filePath, JSON.stringify(record, null, 2), 'utf-8')\n}\n\nexport const DEFAULT_PASSWORD = 'Chang3M3Now!'\n\nexport function initAdmin(): { password: string; apiKey: string; isNew: boolean } {\n const existing = loadAdmin()\n if (existing) return { password: '', apiKey: '', isNew: false }\n\n const apiKey = generateApiKey()\n saveAdmin({\n passwordHash: hashPassword(DEFAULT_PASSWORD),\n isDefaultPassword: true,\n createdAt: new Date().toISOString(),\n lastLoginAt: null,\n apiKey: encryptApiKey(apiKey),\n })\n return { password: DEFAULT_PASSWORD, apiKey, isNew: true }\n}\n\nexport function verifyPassword(password: string): boolean {\n const record = loadAdmin()\n if (!record) return false\n return record.passwordHash === hashPassword(password)\n}\n\nexport function updatePassword(newPassword: string): void {\n const record = loadAdmin()\n if (!record) return\n saveAdmin({\n ...record,\n passwordHash: hashPassword(newPassword),\n isDefaultPassword: false,\n })\n}\n\nexport function recordLogin(): void {\n const record = loadAdmin()\n if (!record) return\n saveAdmin({ ...record, lastLoginAt: new Date().toISOString() })\n}\n\n// ---------------------------------------------------------------------------\n// API key — AES-256-GCM encrypted at rest, mirroring WP's SECURE_AUTH_KEY approach\n// ---------------------------------------------------------------------------\n\nconst CIPHER = 'aes-256-gcm'\n\nfunction getEncryptionKey(): Buffer {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-fallback-key-change-me'\n // Derive a 32-byte key from the secret using SHA-256\n return crypto.createHash('sha256').update(secret).digest()\n}\n\nfunction encryptApiKey(plaintext: string): string {\n const iv = crypto.randomBytes(12)\n const key = getEncryptionKey()\n const cipher = crypto.createCipheriv(CIPHER, key, iv) as crypto.CipherGCM\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])\n const tag = cipher.getAuthTag()\n // Format: iv(24 hex) + tag(32 hex) + encrypted(hex)\n return iv.toString('hex') + tag.toString('hex') + encrypted.toString('hex')\n}\n\nfunction decryptApiKey(encoded: string): string | null {\n try {\n const iv = Buffer.from(encoded.slice(0, 24), 'hex')\n const tag = Buffer.from(encoded.slice(24, 56), 'hex')\n const encrypted = Buffer.from(encoded.slice(56), 'hex')\n const key = getEncryptionKey()\n const decipher = crypto.createDecipheriv(CIPHER, key, iv) as crypto.DecipherGCM\n decipher.setAuthTag(tag)\n return decipher.update(encrypted) + decipher.final('utf8')\n } catch {\n return null\n }\n}\n\nexport function generateApiKey(): string {\n return 'ta_' + crypto.randomBytes(24).toString('hex') // 51-char key\n}\n\nexport function getApiKey(): string | null {\n const record = loadAdmin()\n if (!record?.apiKey) return null\n return decryptApiKey(record.apiKey)\n}\n\nexport function rotateApiKey(): string {\n const record = loadAdmin()\n if (!record) throw new Error('Admin store not initialised')\n const newKey = generateApiKey()\n saveAdmin({ ...record, apiKey: encryptApiKey(newKey) })\n return newKey\n}\n\nexport function verifyApiKey(key: string): boolean {\n const stored = getApiKey()\n if (!stored) return false\n if (key.length !== stored.length) return false\n return crypto.timingSafeEqual(Buffer.from(key), Buffer.from(stored))\n}\n\n// ---------------------------------------------------------------------------\n// Session cookie: HMAC-SHA256(secret, userId + timestamp) — stateless, no DB\n// ---------------------------------------------------------------------------\nexport function signSession(payload: string): string {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt'\n const sig = crypto.createHmac('sha256', secret).update(payload).digest('hex')\n return `${payload}.${sig}`\n}\n\nexport function verifySession(token: string): boolean {\n const lastDot = token.lastIndexOf('.')\n if (lastDot === -1) return false\n const payload = token.slice(0, lastDot)\n const sig = token.slice(lastDot + 1)\n const expected = crypto.createHmac('sha256', process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt')\n .update(payload).digest('hex')\n // Constant-time comparison\n if (sig.length !== expected.length) return false\n return crypto.timingSafeEqual(Buffer.from(sig, 'hex'), Buffer.from(expected, 'hex'))\n}\n"],"mappings":"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","names":["path","crypto","fs"]}
@@ -0,0 +1,142 @@
1
+ // src/dashboard/admin-store.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import crypto from "crypto";
5
+ function adminFilePath() {
6
+ const dataDir = process.env.TA_DATA_DIR ?? "data";
7
+ return path.join(process.cwd(), dataDir, "ta-admin.json");
8
+ }
9
+ function generateDefaultPassword() {
10
+ return crypto.randomBytes(6).toString("hex");
11
+ }
12
+ function hashPassword(password) {
13
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt";
14
+ return crypto.createHash("sha256").update(secret + password).digest("hex");
15
+ }
16
+ function loadAdmin() {
17
+ const filePath = adminFilePath();
18
+ if (!fs.existsSync(filePath)) return null;
19
+ try {
20
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+ function saveAdmin(record) {
26
+ const filePath = adminFilePath();
27
+ const dir = path.dirname(filePath);
28
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
29
+ fs.writeFileSync(filePath, JSON.stringify(record, null, 2), "utf-8");
30
+ }
31
+ var DEFAULT_PASSWORD = "Chang3M3Now!";
32
+ function initAdmin() {
33
+ const existing = loadAdmin();
34
+ if (existing) return { password: "", apiKey: "", isNew: false };
35
+ const apiKey = generateApiKey();
36
+ saveAdmin({
37
+ passwordHash: hashPassword(DEFAULT_PASSWORD),
38
+ isDefaultPassword: true,
39
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
40
+ lastLoginAt: null,
41
+ apiKey: encryptApiKey(apiKey)
42
+ });
43
+ return { password: DEFAULT_PASSWORD, apiKey, isNew: true };
44
+ }
45
+ function verifyPassword(password) {
46
+ const record = loadAdmin();
47
+ if (!record) return false;
48
+ return record.passwordHash === hashPassword(password);
49
+ }
50
+ function updatePassword(newPassword) {
51
+ const record = loadAdmin();
52
+ if (!record) return;
53
+ saveAdmin({
54
+ ...record,
55
+ passwordHash: hashPassword(newPassword),
56
+ isDefaultPassword: false
57
+ });
58
+ }
59
+ function recordLogin() {
60
+ const record = loadAdmin();
61
+ if (!record) return;
62
+ saveAdmin({ ...record, lastLoginAt: (/* @__PURE__ */ new Date()).toISOString() });
63
+ }
64
+ var CIPHER = "aes-256-gcm";
65
+ function getEncryptionKey() {
66
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-fallback-key-change-me";
67
+ return crypto.createHash("sha256").update(secret).digest();
68
+ }
69
+ function encryptApiKey(plaintext) {
70
+ const iv = crypto.randomBytes(12);
71
+ const key = getEncryptionKey();
72
+ const cipher = crypto.createCipheriv(CIPHER, key, iv);
73
+ const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
74
+ const tag = cipher.getAuthTag();
75
+ return iv.toString("hex") + tag.toString("hex") + encrypted.toString("hex");
76
+ }
77
+ function decryptApiKey(encoded) {
78
+ try {
79
+ const iv = Buffer.from(encoded.slice(0, 24), "hex");
80
+ const tag = Buffer.from(encoded.slice(24, 56), "hex");
81
+ const encrypted = Buffer.from(encoded.slice(56), "hex");
82
+ const key = getEncryptionKey();
83
+ const decipher = crypto.createDecipheriv(CIPHER, key, iv);
84
+ decipher.setAuthTag(tag);
85
+ return decipher.update(encrypted) + decipher.final("utf8");
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+ function generateApiKey() {
91
+ return "ta_" + crypto.randomBytes(24).toString("hex");
92
+ }
93
+ function getApiKey() {
94
+ const record = loadAdmin();
95
+ if (!record?.apiKey) return null;
96
+ return decryptApiKey(record.apiKey);
97
+ }
98
+ function rotateApiKey() {
99
+ const record = loadAdmin();
100
+ if (!record) throw new Error("Admin store not initialised");
101
+ const newKey = generateApiKey();
102
+ saveAdmin({ ...record, apiKey: encryptApiKey(newKey) });
103
+ return newKey;
104
+ }
105
+ function verifyApiKey(key) {
106
+ const stored = getApiKey();
107
+ if (!stored) return false;
108
+ if (key.length !== stored.length) return false;
109
+ return crypto.timingSafeEqual(Buffer.from(key), Buffer.from(stored));
110
+ }
111
+ function signSession(payload) {
112
+ const secret = process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt";
113
+ const sig = crypto.createHmac("sha256", secret).update(payload).digest("hex");
114
+ return `${payload}.${sig}`;
115
+ }
116
+ function verifySession(token) {
117
+ const lastDot = token.lastIndexOf(".");
118
+ if (lastDot === -1) return false;
119
+ const payload = token.slice(0, lastDot);
120
+ const sig = token.slice(lastDot + 1);
121
+ const expected = crypto.createHmac("sha256", process.env.THIRD_AUDIENCE_SECRET ?? "ta-salt").update(payload).digest("hex");
122
+ if (sig.length !== expected.length) return false;
123
+ return crypto.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"));
124
+ }
125
+ export {
126
+ DEFAULT_PASSWORD,
127
+ generateApiKey,
128
+ generateDefaultPassword,
129
+ getApiKey,
130
+ hashPassword,
131
+ initAdmin,
132
+ loadAdmin,
133
+ recordLogin,
134
+ rotateApiKey,
135
+ saveAdmin,
136
+ signSession,
137
+ updatePassword,
138
+ verifyApiKey,
139
+ verifyPassword,
140
+ verifySession
141
+ };
142
+ //# sourceMappingURL=admin-store.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dashboard/admin-store.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport crypto from 'crypto'\n\nexport interface AdminRecord {\n passwordHash: string // sha256(secret + password)\n isDefaultPassword: boolean\n createdAt: string\n lastLoginAt: string | null\n apiKey?: string // AES-256-GCM encrypted, for headless/external API callers\n}\n\nfunction adminFilePath(): string {\n const dataDir = process.env.TA_DATA_DIR ?? 'data'\n return path.join(process.cwd(), dataDir, 'ta-admin.json')\n}\n\nexport function generateDefaultPassword(): string {\n return crypto.randomBytes(6).toString('hex') // 12-char hex, easy to type\n}\n\nexport function hashPassword(password: string): string {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt'\n return crypto.createHash('sha256').update(secret + password).digest('hex')\n}\n\nexport function loadAdmin(): AdminRecord | null {\n const filePath = adminFilePath()\n if (!fs.existsSync(filePath)) return null\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8')) as AdminRecord\n } catch {\n return null\n }\n}\n\nexport function saveAdmin(record: AdminRecord): void {\n const filePath = adminFilePath()\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(filePath, JSON.stringify(record, null, 2), 'utf-8')\n}\n\nexport const DEFAULT_PASSWORD = 'Chang3M3Now!'\n\nexport function initAdmin(): { password: string; apiKey: string; isNew: boolean } {\n const existing = loadAdmin()\n if (existing) return { password: '', apiKey: '', isNew: false }\n\n const apiKey = generateApiKey()\n saveAdmin({\n passwordHash: hashPassword(DEFAULT_PASSWORD),\n isDefaultPassword: true,\n createdAt: new Date().toISOString(),\n lastLoginAt: null,\n apiKey: encryptApiKey(apiKey),\n })\n return { password: DEFAULT_PASSWORD, apiKey, isNew: true }\n}\n\nexport function verifyPassword(password: string): boolean {\n const record = loadAdmin()\n if (!record) return false\n return record.passwordHash === hashPassword(password)\n}\n\nexport function updatePassword(newPassword: string): void {\n const record = loadAdmin()\n if (!record) return\n saveAdmin({\n ...record,\n passwordHash: hashPassword(newPassword),\n isDefaultPassword: false,\n })\n}\n\nexport function recordLogin(): void {\n const record = loadAdmin()\n if (!record) return\n saveAdmin({ ...record, lastLoginAt: new Date().toISOString() })\n}\n\n// ---------------------------------------------------------------------------\n// API key — AES-256-GCM encrypted at rest, mirroring WP's SECURE_AUTH_KEY approach\n// ---------------------------------------------------------------------------\n\nconst CIPHER = 'aes-256-gcm'\n\nfunction getEncryptionKey(): Buffer {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-fallback-key-change-me'\n // Derive a 32-byte key from the secret using SHA-256\n return crypto.createHash('sha256').update(secret).digest()\n}\n\nfunction encryptApiKey(plaintext: string): string {\n const iv = crypto.randomBytes(12)\n const key = getEncryptionKey()\n const cipher = crypto.createCipheriv(CIPHER, key, iv) as crypto.CipherGCM\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])\n const tag = cipher.getAuthTag()\n // Format: iv(24 hex) + tag(32 hex) + encrypted(hex)\n return iv.toString('hex') + tag.toString('hex') + encrypted.toString('hex')\n}\n\nfunction decryptApiKey(encoded: string): string | null {\n try {\n const iv = Buffer.from(encoded.slice(0, 24), 'hex')\n const tag = Buffer.from(encoded.slice(24, 56), 'hex')\n const encrypted = Buffer.from(encoded.slice(56), 'hex')\n const key = getEncryptionKey()\n const decipher = crypto.createDecipheriv(CIPHER, key, iv) as crypto.DecipherGCM\n decipher.setAuthTag(tag)\n return decipher.update(encrypted) + decipher.final('utf8')\n } catch {\n return null\n }\n}\n\nexport function generateApiKey(): string {\n return 'ta_' + crypto.randomBytes(24).toString('hex') // 51-char key\n}\n\nexport function getApiKey(): string | null {\n const record = loadAdmin()\n if (!record?.apiKey) return null\n return decryptApiKey(record.apiKey)\n}\n\nexport function rotateApiKey(): string {\n const record = loadAdmin()\n if (!record) throw new Error('Admin store not initialised')\n const newKey = generateApiKey()\n saveAdmin({ ...record, apiKey: encryptApiKey(newKey) })\n return newKey\n}\n\nexport function verifyApiKey(key: string): boolean {\n const stored = getApiKey()\n if (!stored) return false\n if (key.length !== stored.length) return false\n return crypto.timingSafeEqual(Buffer.from(key), Buffer.from(stored))\n}\n\n// ---------------------------------------------------------------------------\n// Session cookie: HMAC-SHA256(secret, userId + timestamp) — stateless, no DB\n// ---------------------------------------------------------------------------\nexport function signSession(payload: string): string {\n const secret = process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt'\n const sig = crypto.createHmac('sha256', secret).update(payload).digest('hex')\n return `${payload}.${sig}`\n}\n\nexport function verifySession(token: string): boolean {\n const lastDot = token.lastIndexOf('.')\n if (lastDot === -1) return false\n const payload = token.slice(0, lastDot)\n const sig = token.slice(lastDot + 1)\n const expected = crypto.createHmac('sha256', process.env.THIRD_AUDIENCE_SECRET ?? 'ta-salt')\n .update(payload).digest('hex')\n // Constant-time comparison\n if (sig.length !== expected.length) return false\n return crypto.timingSafeEqual(Buffer.from(sig, 'hex'), Buffer.from(expected, 'hex'))\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,YAAY;AAUnB,SAAS,gBAAwB;AAC/B,QAAM,UAAU,QAAQ,IAAI,eAAe;AAC3C,SAAO,KAAK,KAAK,QAAQ,IAAI,GAAG,SAAS,eAAe;AAC1D;AAEO,SAAS,0BAAkC;AAChD,SAAO,OAAO,YAAY,CAAC,EAAE,SAAS,KAAK;AAC7C;AAEO,SAAS,aAAa,UAA0B;AACrD,QAAM,SAAS,QAAQ,IAAI,yBAAyB;AACpD,SAAO,OAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,QAAQ,EAAE,OAAO,KAAK;AAC3E;AAEO,SAAS,YAAgC;AAC9C,QAAM,WAAW,cAAc;AAC/B,MAAI,CAAC,GAAG,WAAW,QAAQ,EAAG,QAAO;AACrC,MAAI;AACF,WAAO,KAAK,MAAM,GAAG,aAAa,UAAU,OAAO,CAAC;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,QAA2B;AACnD,QAAM,WAAW,cAAc;AAC/B,QAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,IAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAC9D,KAAG,cAAc,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AACrE;AAEO,IAAM,mBAAmB;AAEzB,SAAS,YAAkE;AAChF,QAAM,WAAW,UAAU;AAC3B,MAAI,SAAU,QAAO,EAAE,UAAU,IAAI,QAAQ,IAAI,OAAO,MAAM;AAE9D,QAAM,SAAS,eAAe;AAC9B,YAAU;AAAA,IACR,cAAc,aAAa,gBAAgB;AAAA,IAC3C,mBAAmB;AAAA,IACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,aAAa;AAAA,IACb,QAAQ,cAAc,MAAM;AAAA,EAC9B,CAAC;AACD,SAAO,EAAE,UAAU,kBAAkB,QAAQ,OAAO,KAAK;AAC3D;AAEO,SAAS,eAAe,UAA2B;AACxD,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OAAO,iBAAiB,aAAa,QAAQ;AACtD;AAEO,SAAS,eAAe,aAA2B;AACxD,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ;AACb,YAAU;AAAA,IACR,GAAG;AAAA,IACH,cAAc,aAAa,WAAW;AAAA,IACtC,mBAAmB;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,cAAoB;AAClC,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ;AACb,YAAU,EAAE,GAAG,QAAQ,cAAa,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC;AAChE;AAMA,IAAM,SAAS;AAEf,SAAS,mBAA2B;AAClC,QAAM,SAAS,QAAQ,IAAI,yBAAyB;AAEpD,SAAO,OAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO;AAC3D;AAEA,SAAS,cAAc,WAA2B;AAChD,QAAM,KAAK,OAAO,YAAY,EAAE;AAChC,QAAM,MAAM,iBAAiB;AAC7B,QAAM,SAAS,OAAO,eAAe,QAAQ,KAAK,EAAE;AACpD,QAAM,YAAY,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AAClF,QAAM,MAAM,OAAO,WAAW;AAE9B,SAAO,GAAG,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,UAAU,SAAS,KAAK;AAC5E;AAEA,SAAS,cAAc,SAAgC;AACrD,MAAI;AACF,UAAM,KAAK,OAAO,KAAK,QAAQ,MAAM,GAAG,EAAE,GAAG,KAAK;AAClD,UAAM,MAAM,OAAO,KAAK,QAAQ,MAAM,IAAI,EAAE,GAAG,KAAK;AACpD,UAAM,YAAY,OAAO,KAAK,QAAQ,MAAM,EAAE,GAAG,KAAK;AACtD,UAAM,MAAM,iBAAiB;AAC7B,UAAM,WAAW,OAAO,iBAAiB,QAAQ,KAAK,EAAE;AACxD,aAAS,WAAW,GAAG;AACvB,WAAO,SAAS,OAAO,SAAS,IAAI,SAAS,MAAM,MAAM;AAAA,EAC3D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,iBAAyB;AACvC,SAAO,QAAQ,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACtD;AAEO,SAAS,YAA2B;AACzC,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,SAAO,cAAc,OAAO,MAAM;AACpC;AAEO,SAAS,eAAuB;AACrC,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6BAA6B;AAC1D,QAAM,SAAS,eAAe;AAC9B,YAAU,EAAE,GAAG,QAAQ,QAAQ,cAAc,MAAM,EAAE,CAAC;AACtD,SAAO;AACT;AAEO,SAAS,aAAa,KAAsB;AACjD,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,IAAI,WAAW,OAAO,OAAQ,QAAO;AACzC,SAAO,OAAO,gBAAgB,OAAO,KAAK,GAAG,GAAG,OAAO,KAAK,MAAM,CAAC;AACrE;AAKO,SAAS,YAAY,SAAyB;AACnD,QAAM,SAAS,QAAQ,IAAI,yBAAyB;AACpD,QAAM,MAAM,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC5E,SAAO,GAAG,OAAO,IAAI,GAAG;AAC1B;AAEO,SAAS,cAAc,OAAwB;AACpD,QAAM,UAAU,MAAM,YAAY,GAAG;AACrC,MAAI,YAAY,GAAI,QAAO;AAC3B,QAAM,UAAU,MAAM,MAAM,GAAG,OAAO;AACtC,QAAM,MAAM,MAAM,MAAM,UAAU,CAAC;AACnC,QAAM,WAAW,OAAO,WAAW,UAAU,QAAQ,IAAI,yBAAyB,SAAS,EACxF,OAAO,OAAO,EAAE,OAAO,KAAK;AAE/B,MAAI,IAAI,WAAW,SAAS,OAAQ,QAAO;AAC3C,SAAO,OAAO,gBAAgB,OAAO,KAAK,KAAK,KAAK,GAAG,OAAO,KAAK,UAAU,KAAK,CAAC;AACrF;","names":[]}
@@ -0,0 +1,11 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface CardProps {
5
+ title: string;
6
+ action?: ReactNode;
7
+ children: ReactNode;
8
+ }
9
+ declare function Card({ title, action, children }: CardProps): react.JSX.Element;
10
+
11
+ export { Card };
@@ -0,0 +1,11 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface CardProps {
5
+ title: string;
6
+ action?: ReactNode;
7
+ children: ReactNode;
8
+ }
9
+ declare function Card({ title, action, children }: CardProps): react.JSX.Element;
10
+
11
+ export { Card };
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/dashboard/ui/components/Card.tsx
21
+ var Card_exports = {};
22
+ __export(Card_exports, {
23
+ Card: () => Card
24
+ });
25
+ module.exports = __toCommonJS(Card_exports);
26
+ var import_jsx_runtime = require("react/jsx-runtime");
27
+ function Card({ title, action, children }) {
28
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card ta-section", children: [
29
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card-header", children: [
30
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
31
+ action
32
+ ] }),
33
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-card-body", children })
34
+ ] });
35
+ }
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ Card
39
+ });
40
+ //# sourceMappingURL=Card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/Card.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\ninterface CardProps {\n title: string\n action?: ReactNode\n children: ReactNode\n}\n\nexport function Card({ title, action, children }: CardProps) {\n return (\n <div className=\"ta-card ta-section\">\n <div className=\"ta-card-header\">\n <h2>{title}</h2>\n {action}\n </div>\n <div className=\"ta-card-body\">{children}</div>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWM;AAHC,SAAS,KAAK,EAAE,OAAO,QAAQ,SAAS,GAAc;AAC3D,SACE,6CAAC,SAAI,WAAU,sBACb;AAAA,iDAAC,SAAI,WAAU,kBACb;AAAA,kDAAC,QAAI,iBAAM;AAAA,MACV;AAAA,OACH;AAAA,IACA,4CAAC,SAAI,WAAU,gBAAgB,UAAS;AAAA,KAC1C;AAEJ;","names":[]}
@@ -0,0 +1,15 @@
1
+ // src/dashboard/ui/components/Card.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function Card({ title, action, children }) {
4
+ return /* @__PURE__ */ jsxs("div", { className: "ta-card ta-section", children: [
5
+ /* @__PURE__ */ jsxs("div", { className: "ta-card-header", children: [
6
+ /* @__PURE__ */ jsx("h2", { children: title }),
7
+ action
8
+ ] }),
9
+ /* @__PURE__ */ jsx("div", { className: "ta-card-body", children })
10
+ ] });
11
+ }
12
+ export {
13
+ Card
14
+ };
15
+ //# sourceMappingURL=Card.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/Card.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\ninterface CardProps {\n title: string\n action?: ReactNode\n children: ReactNode\n}\n\nexport function Card({ title, action, children }: CardProps) {\n return (\n <div className=\"ta-card ta-section\">\n <div className=\"ta-card-header\">\n <h2>{title}</h2>\n {action}\n </div>\n <div className=\"ta-card-body\">{children}</div>\n </div>\n )\n}\n"],"mappings":";AAWM,SACE,KADF;AAHC,SAAS,KAAK,EAAE,OAAO,QAAQ,SAAS,GAAc;AAC3D,SACE,qBAAC,SAAI,WAAU,sBACb;AAAA,yBAAC,SAAI,WAAU,kBACb;AAAA,0BAAC,QAAI,iBAAM;AAAA,MACV;AAAA,OACH;AAAA,IACA,oBAAC,SAAI,WAAU,gBAAgB,UAAS;AAAA,KAC1C;AAEJ;","names":[]}
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface HeroCardProps {
5
+ label: string;
6
+ value: string | number;
7
+ meta?: string;
8
+ color?: 'blue' | 'green' | 'orange' | 'teal';
9
+ icon: ReactNode;
10
+ }
11
+ declare function HeroCard({ label, value, meta, color, icon }: HeroCardProps): react.JSX.Element;
12
+
13
+ export { HeroCard };
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface HeroCardProps {
5
+ label: string;
6
+ value: string | number;
7
+ meta?: string;
8
+ color?: 'blue' | 'green' | 'orange' | 'teal';
9
+ icon: ReactNode;
10
+ }
11
+ declare function HeroCard({ label, value, meta, color, icon }: HeroCardProps): react.JSX.Element;
12
+
13
+ export { HeroCard };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/dashboard/ui/components/HeroCard.tsx
21
+ var HeroCard_exports = {};
22
+ __export(HeroCard_exports, {
23
+ HeroCard: () => HeroCard
24
+ });
25
+ module.exports = __toCommonJS(HeroCard_exports);
26
+ var import_jsx_runtime = require("react/jsx-runtime");
27
+ function HeroCard({ label, value, meta, color = "blue", icon }) {
28
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `ta-hero-card ta-hero-card--${color}`, children: [
29
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-icon", children: icon }),
30
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
31
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-label", children: label }),
32
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-value", children: value }),
33
+ meta && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-meta", children: meta })
34
+ ] })
35
+ ] });
36
+ }
37
+ // Annotate the CommonJS export names for ESM import in node:
38
+ 0 && (module.exports = {
39
+ HeroCard
40
+ });
41
+ //# sourceMappingURL=HeroCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/HeroCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\ninterface HeroCardProps {\n label: string\n value: string | number\n meta?: string\n color?: 'blue' | 'green' | 'orange' | 'teal'\n icon: ReactNode\n}\n\nexport function HeroCard({ label, value, meta, color = 'blue', icon }: HeroCardProps) {\n return (\n <div className={`ta-hero-card ta-hero-card--${color}`}>\n <div className=\"ta-hero-icon\">{icon}</div>\n <div>\n <div className=\"ta-hero-label\">{label}</div>\n <div className=\"ta-hero-value\">{value}</div>\n {meta && <div className=\"ta-hero-meta\">{meta}</div>}\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaM;AAHC,SAAS,SAAS,EAAE,OAAO,OAAO,MAAM,QAAQ,QAAQ,KAAK,GAAkB;AACpF,SACE,6CAAC,SAAI,WAAW,8BAA8B,KAAK,IACjD;AAAA,gDAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,IACpC,6CAAC,SACC;AAAA,kDAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACtC,4CAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACrC,QAAQ,4CAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,OAC/C;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,16 @@
1
+ // src/dashboard/ui/components/HeroCard.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function HeroCard({ label, value, meta, color = "blue", icon }) {
4
+ return /* @__PURE__ */ jsxs("div", { className: `ta-hero-card ta-hero-card--${color}`, children: [
5
+ /* @__PURE__ */ jsx("div", { className: "ta-hero-icon", children: icon }),
6
+ /* @__PURE__ */ jsxs("div", { children: [
7
+ /* @__PURE__ */ jsx("div", { className: "ta-hero-label", children: label }),
8
+ /* @__PURE__ */ jsx("div", { className: "ta-hero-value", children: value }),
9
+ meta && /* @__PURE__ */ jsx("div", { className: "ta-hero-meta", children: meta })
10
+ ] })
11
+ ] });
12
+ }
13
+ export {
14
+ HeroCard
15
+ };
16
+ //# sourceMappingURL=HeroCard.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/HeroCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\ninterface HeroCardProps {\n label: string\n value: string | number\n meta?: string\n color?: 'blue' | 'green' | 'orange' | 'teal'\n icon: ReactNode\n}\n\nexport function HeroCard({ label, value, meta, color = 'blue', icon }: HeroCardProps) {\n return (\n <div className={`ta-hero-card ta-hero-card--${color}`}>\n <div className=\"ta-hero-icon\">{icon}</div>\n <div>\n <div className=\"ta-hero-label\">{label}</div>\n <div className=\"ta-hero-value\">{value}</div>\n {meta && <div className=\"ta-hero-meta\">{meta}</div>}\n </div>\n </div>\n )\n}\n"],"mappings":";AAaM,cACA,YADA;AAHC,SAAS,SAAS,EAAE,OAAO,OAAO,MAAM,QAAQ,QAAQ,KAAK,GAAkB;AACpF,SACE,qBAAC,SAAI,WAAW,8BAA8B,KAAK,IACjD;AAAA,wBAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,IACpC,qBAAC,SACC;AAAA,0BAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACtC,oBAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACrC,QAAQ,oBAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,OAC/C;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+
3
+ interface DayData {
4
+ date: string;
5
+ visits: number;
6
+ }
7
+ interface VisitsChartProps {
8
+ data: DayData[];
9
+ height?: number;
10
+ }
11
+ declare function VisitsChart({ data, height }: VisitsChartProps): react.JSX.Element;
12
+
13
+ export { VisitsChart };
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+
3
+ interface DayData {
4
+ date: string;
5
+ visits: number;
6
+ }
7
+ interface VisitsChartProps {
8
+ data: DayData[];
9
+ height?: number;
10
+ }
11
+ declare function VisitsChart({ data, height }: VisitsChartProps): react.JSX.Element;
12
+
13
+ export { VisitsChart };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/dashboard/ui/components/VisitsChart.tsx
22
+ var VisitsChart_exports = {};
23
+ __export(VisitsChart_exports, {
24
+ VisitsChart: () => VisitsChart
25
+ });
26
+ module.exports = __toCommonJS(VisitsChart_exports);
27
+ var import_jsx_runtime = require("react/jsx-runtime");
28
+ function VisitsChart({ data, height = 160 }) {
29
+ if (!data.length) {
30
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-empty", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "No visit data yet." }) });
31
+ }
32
+ const max = Math.max(...data.map((d) => d.visits), 1);
33
+ const barWidth = Math.max(4, Math.floor(560 / data.length) - 2);
34
+ const showLabel = data.length <= 14;
35
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
36
+ "svg",
37
+ {
38
+ width: "100%",
39
+ viewBox: `0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`,
40
+ style: { display: "block", minWidth: 320 },
41
+ children: data.map((d, i) => {
42
+ const barH = Math.max(2, Math.round(d.visits / max * height));
43
+ const x = i * (barWidth + 2);
44
+ const y = height - barH;
45
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
46
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
47
+ "rect",
48
+ {
49
+ x,
50
+ y,
51
+ width: barWidth,
52
+ height: barH,
53
+ rx: 3,
54
+ fill: "var(--ta-blue)",
55
+ opacity: 0.85,
56
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("title", { children: `${d.date}: ${d.visits} visits` })
57
+ }
58
+ ),
59
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
60
+ "text",
61
+ {
62
+ x: x + barWidth / 2,
63
+ y: height + 16,
64
+ textAnchor: "middle",
65
+ fontSize: 9,
66
+ fill: "var(--ta-gray-500)",
67
+ children: [
68
+ d.date.slice(5),
69
+ " "
70
+ ]
71
+ }
72
+ )
73
+ ] }, d.date);
74
+ })
75
+ }
76
+ ) });
77
+ }
78
+ // Annotate the CommonJS export names for ESM import in node:
79
+ 0 && (module.exports = {
80
+ VisitsChart
81
+ });
82
+ //# sourceMappingURL=VisitsChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/VisitsChart.tsx"],"sourcesContent":["'use client'\n\ninterface DayData { date: string; visits: number }\n\ninterface VisitsChartProps {\n data: DayData[]\n height?: number\n}\n\nexport function VisitsChart({ data, height = 160 }: VisitsChartProps) {\n if (!data.length) {\n return <div className=\"ta-empty\"><p>No visit data yet.</p></div>\n }\n\n const max = Math.max(...data.map(d => d.visits), 1)\n const barWidth = Math.max(4, Math.floor(560 / data.length) - 2)\n const showLabel = data.length <= 14\n\n return (\n <div style={{ overflowX: 'auto' }}>\n <svg\n width=\"100%\"\n viewBox={`0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`}\n style={{ display: 'block', minWidth: 320 }}\n >\n {data.map((d, i) => {\n const barH = Math.max(2, Math.round((d.visits / max) * height))\n const x = i * (barWidth + 2)\n const y = height - barH\n return (\n <g key={d.date}>\n <rect\n x={x} y={y}\n width={barWidth} height={barH}\n rx={3}\n fill=\"var(--ta-blue)\"\n opacity={0.85}\n >\n <title>{`${d.date}: ${d.visits} visits`}</title>\n </rect>\n {showLabel && (\n <text\n x={x + barWidth / 2} y={height + 16}\n textAnchor=\"middle\"\n fontSize={9}\n fill=\"var(--ta-gray-500)\"\n >\n {d.date.slice(5)} {/* MM-DD */}\n </text>\n )}\n </g>\n )\n })}\n </svg>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWqC;AAF9B,SAAS,YAAY,EAAE,MAAM,SAAS,IAAI,GAAqB;AACpE,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAO,4CAAC,SAAI,WAAU,YAAW,sDAAC,OAAE,gCAAkB,GAAI;AAAA,EAC5D;AAEA,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAK,EAAE,MAAM,GAAG,CAAC;AAClD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,KAAK,MAAM,IAAI,CAAC;AAC9D,QAAM,YAAY,KAAK,UAAU;AAEjC,SACE,4CAAC,SAAI,OAAO,EAAE,WAAW,OAAO,GAC9B;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,SAAS,OAAO,KAAK,IAAI,KAAK,UAAU,WAAW,IAAI,GAAG,CAAC,IAAI,SAAS,EAAE;AAAA,MAC1E,OAAO,EAAE,SAAS,SAAS,UAAU,IAAI;AAAA,MAExC,eAAK,IAAI,CAAC,GAAG,MAAM;AAClB,cAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAO,EAAE,SAAS,MAAO,MAAM,CAAC;AAC9D,cAAM,IAAI,KAAK,WAAW;AAC1B,cAAM,IAAI,SAAS;AACnB,eACE,6CAAC,OACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cAAM;AAAA,cACN,OAAO;AAAA,cAAU,QAAQ;AAAA,cACzB,IAAI;AAAA,cACJ,MAAK;AAAA,cACL,SAAS;AAAA,cAET,sDAAC,WAAO,aAAG,EAAE,IAAI,KAAK,EAAE,MAAM,WAAU;AAAA;AAAA,UAC1C;AAAA,UACC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,GAAG,IAAI,WAAW;AAAA,cAAG,GAAG,SAAS;AAAA,cACjC,YAAW;AAAA,cACX,UAAU;AAAA,cACV,MAAK;AAAA,cAEJ;AAAA,kBAAE,KAAK,MAAM,CAAC;AAAA,gBAAE;AAAA;AAAA;AAAA,UACnB;AAAA,aAlBI,EAAE,IAoBV;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH,GACF;AAEJ;","names":[]}
@@ -0,0 +1,58 @@
1
+ "use client";
2
+
3
+ // src/dashboard/ui/components/VisitsChart.tsx
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ function VisitsChart({ data, height = 160 }) {
6
+ if (!data.length) {
7
+ return /* @__PURE__ */ jsx("div", { className: "ta-empty", children: /* @__PURE__ */ jsx("p", { children: "No visit data yet." }) });
8
+ }
9
+ const max = Math.max(...data.map((d) => d.visits), 1);
10
+ const barWidth = Math.max(4, Math.floor(560 / data.length) - 2);
11
+ const showLabel = data.length <= 14;
12
+ return /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsx(
13
+ "svg",
14
+ {
15
+ width: "100%",
16
+ viewBox: `0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`,
17
+ style: { display: "block", minWidth: 320 },
18
+ children: data.map((d, i) => {
19
+ const barH = Math.max(2, Math.round(d.visits / max * height));
20
+ const x = i * (barWidth + 2);
21
+ const y = height - barH;
22
+ return /* @__PURE__ */ jsxs("g", { children: [
23
+ /* @__PURE__ */ jsx(
24
+ "rect",
25
+ {
26
+ x,
27
+ y,
28
+ width: barWidth,
29
+ height: barH,
30
+ rx: 3,
31
+ fill: "var(--ta-blue)",
32
+ opacity: 0.85,
33
+ children: /* @__PURE__ */ jsx("title", { children: `${d.date}: ${d.visits} visits` })
34
+ }
35
+ ),
36
+ showLabel && /* @__PURE__ */ jsxs(
37
+ "text",
38
+ {
39
+ x: x + barWidth / 2,
40
+ y: height + 16,
41
+ textAnchor: "middle",
42
+ fontSize: 9,
43
+ fill: "var(--ta-gray-500)",
44
+ children: [
45
+ d.date.slice(5),
46
+ " "
47
+ ]
48
+ }
49
+ )
50
+ ] }, d.date);
51
+ })
52
+ }
53
+ ) });
54
+ }
55
+ export {
56
+ VisitsChart
57
+ };
58
+ //# sourceMappingURL=VisitsChart.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/components/VisitsChart.tsx"],"sourcesContent":["'use client'\n\ninterface DayData { date: string; visits: number }\n\ninterface VisitsChartProps {\n data: DayData[]\n height?: number\n}\n\nexport function VisitsChart({ data, height = 160 }: VisitsChartProps) {\n if (!data.length) {\n return <div className=\"ta-empty\"><p>No visit data yet.</p></div>\n }\n\n const max = Math.max(...data.map(d => d.visits), 1)\n const barWidth = Math.max(4, Math.floor(560 / data.length) - 2)\n const showLabel = data.length <= 14\n\n return (\n <div style={{ overflowX: 'auto' }}>\n <svg\n width=\"100%\"\n viewBox={`0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`}\n style={{ display: 'block', minWidth: 320 }}\n >\n {data.map((d, i) => {\n const barH = Math.max(2, Math.round((d.visits / max) * height))\n const x = i * (barWidth + 2)\n const y = height - barH\n return (\n <g key={d.date}>\n <rect\n x={x} y={y}\n width={barWidth} height={barH}\n rx={3}\n fill=\"var(--ta-blue)\"\n opacity={0.85}\n >\n <title>{`${d.date}: ${d.visits} visits`}</title>\n </rect>\n {showLabel && (\n <text\n x={x + barWidth / 2} y={height + 16}\n textAnchor=\"middle\"\n fontSize={9}\n fill=\"var(--ta-gray-500)\"\n >\n {d.date.slice(5)} {/* MM-DD */}\n </text>\n )}\n </g>\n )\n })}\n </svg>\n </div>\n )\n}\n"],"mappings":";;;AAWqC,cA8BrB,YA9BqB;AAF9B,SAAS,YAAY,EAAE,MAAM,SAAS,IAAI,GAAqB;AACpE,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAO,oBAAC,SAAI,WAAU,YAAW,8BAAC,OAAE,gCAAkB,GAAI;AAAA,EAC5D;AAEA,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAK,EAAE,MAAM,GAAG,CAAC;AAClD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,KAAK,MAAM,IAAI,CAAC;AAC9D,QAAM,YAAY,KAAK,UAAU;AAEjC,SACE,oBAAC,SAAI,OAAO,EAAE,WAAW,OAAO,GAC9B;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,SAAS,OAAO,KAAK,IAAI,KAAK,UAAU,WAAW,IAAI,GAAG,CAAC,IAAI,SAAS,EAAE;AAAA,MAC1E,OAAO,EAAE,SAAS,SAAS,UAAU,IAAI;AAAA,MAExC,eAAK,IAAI,CAAC,GAAG,MAAM;AAClB,cAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAO,EAAE,SAAS,MAAO,MAAM,CAAC;AAC9D,cAAM,IAAI,KAAK,WAAW;AAC1B,cAAM,IAAI,SAAS;AACnB,eACE,qBAAC,OACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cAAM;AAAA,cACN,OAAO;AAAA,cAAU,QAAQ;AAAA,cACzB,IAAI;AAAA,cACJ,MAAK;AAAA,cACL,SAAS;AAAA,cAET,8BAAC,WAAO,aAAG,EAAE,IAAI,KAAK,EAAE,MAAM,WAAU;AAAA;AAAA,UAC1C;AAAA,UACC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,GAAG,IAAI,WAAW;AAAA,cAAG,GAAG,SAAS;AAAA,cACjC,YAAW;AAAA,cACX,UAAU;AAAA,cACV,MAAK;AAAA,cAEJ;AAAA,kBAAE,KAAK,MAAM,CAAC;AAAA,gBAAE;AAAA;AAAA;AAAA,UACnB;AAAA,aAlBI,EAAE,IAoBV;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH,GACF;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "third-audience-mdx",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Serve AI-optimized Markdown to LLM crawlers from MDX content sites. Track bot visits, citations, and AI discoverability.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -112,7 +112,7 @@
112
112
  "third-audience": "./dist/cli/index.js"
113
113
  },
114
114
  "scripts": {
115
- "build": "tsup src/index.ts src/cli/index.ts src/dashboard/routes/*.ts src/dashboard/auth.ts src/dashboard/ui/components/Sidebar.tsx src/dashboard/ui/pages/*.tsx --format cjs,esm --dts --clean",
115
+ "build": "tsup",
116
116
  "dev": "tsup src/index.ts --watch",
117
117
  "typecheck": "tsc --noEmit",
118
118
  "test": "vitest run",