yamchart 0.9.4 → 0.9.5
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/dist/{chunk-7CD6UQAV.js → chunk-DZVT6PHW.js} +9 -1
- package/dist/chunk-DZVT6PHW.js.map +1 -0
- package/dist/{dev-7YLRQ6SA.js → dev-GWXHBBWB.js} +21 -6
- package/dist/{dev-7YLRQ6SA.js.map → dev-GWXHBBWB.js.map} +1 -1
- package/dist/{dist-NGQG7Z4G.js → dist-MIKFZKSD.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/public/assets/{EventManagement-B7leMxfo.js → EventManagement-CTuAJ0eF.js} +1 -1
- package/dist/public/assets/{ExplorePage-zI1OiYlH.js → ExplorePage-ZJ3zNjNQ.js} +1 -1
- package/dist/public/assets/{LoginPage-Dyk2ILmo.js → LoginPage-wygea4BI.js} +1 -1
- package/dist/public/assets/{PublicViewer-C2tNYBR2.js → PublicViewer-8YqGrVVB.js} +1 -1
- package/dist/public/assets/{SetupWizard-BzZSJlbt.js → SetupWizard-DqDBwHrF.js} +1 -1
- package/dist/public/assets/{ShareManagement-C7RIZRWe.js → ShareManagement-TAAdI_gY.js} +1 -1
- package/dist/public/assets/{UserManagement-BD-lLbVH.js → UserManagement-B4kZHyri.js} +1 -1
- package/dist/public/assets/{index-lklRbe2I.js → index-BgzSjgIu.js} +3 -3
- package/dist/public/assets/{index.es-CLyC5-GY.js → index.es-AB-GdGyc.js} +1 -1
- package/dist/public/assets/{jspdf.es.min-CTZVk96E.js → jspdf.es.min-ChRx2mOQ.js} +3 -3
- package/dist/public/index.html +1 -1
- package/dist/{reset-password-HDCLH7PZ.js → reset-password-YVCZKZPC.js} +2 -2
- package/dist/templates/default/docs/yamchart-reference.md +4 -0
- package/package.json +4 -4
- package/dist/chunk-7CD6UQAV.js.map +0 -1
- /package/dist/{dist-NGQG7Z4G.js.map → dist-MIKFZKSD.js.map} +0 -0
- /package/dist/{reset-password-HDCLH7PZ.js.map → reset-password-YVCZKZPC.js.map} +0 -0
|
@@ -165,6 +165,14 @@ var AuthDatabase = class {
|
|
|
165
165
|
sets.push("password_hash = ?");
|
|
166
166
|
values.push(input.password_hash);
|
|
167
167
|
}
|
|
168
|
+
if (input.provider !== void 0) {
|
|
169
|
+
sets.push("provider = ?");
|
|
170
|
+
values.push(input.provider);
|
|
171
|
+
}
|
|
172
|
+
if (input.external_id !== void 0) {
|
|
173
|
+
sets.push("external_id = ?");
|
|
174
|
+
values.push(input.external_id);
|
|
175
|
+
}
|
|
168
176
|
if (sets.length === 0)
|
|
169
177
|
return;
|
|
170
178
|
sets.push("updated_at = ?");
|
|
@@ -344,4 +352,4 @@ export {
|
|
|
344
352
|
generateOpaqueToken,
|
|
345
353
|
hashToken
|
|
346
354
|
};
|
|
347
|
-
//# sourceMappingURL=chunk-
|
|
355
|
+
//# sourceMappingURL=chunk-DZVT6PHW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/auth-local/src/passwords.ts","../../../packages/auth-local/src/database.ts","../../../packages/auth-local/src/sessions.ts","../../../packages/auth-local/src/oauth-crypto.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\n\nconst SALT_ROUNDS = 12;\n\nexport async function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, SALT_ROUNDS);\n}\n\nexport async function verifyPassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n}\n","import Database from 'better-sqlite3';\nimport { randomBytes } from 'crypto';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { LocalUser, SafeUser, Role, Provider, Session, ShareLink, CreateShareLinkInput } from './types.js';\nimport type {\n OAuthClient, RegisterOAuthClientInput,\n OAuthAuthCode, CreateAuthCodeInput,\n OAuthToken, OAuthTokenType, CreateOAuthTokenInput,\n} from './oauth-types.js';\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT UNIQUE NOT NULL,\n name TEXT NOT NULL,\n password_hash TEXT,\n role TEXT NOT NULL DEFAULT 'viewer',\n provider TEXT NOT NULL DEFAULT 'local',\n external_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE(provider, external_id)\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS password_reset_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token TEXT UNIQUE NOT NULL,\n expires_at TEXT NOT NULL,\n used INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS share_links (\n id TEXT PRIMARY KEY,\n token TEXT UNIQUE NOT NULL,\n resource_type TEXT NOT NULL,\n resource_name TEXT NOT NULL,\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n expires_at TEXT,\n is_active INTEGER NOT NULL DEFAULT 1\n);\n\nCREATE TABLE IF NOT EXISTS oauth_clients (\n client_id TEXT PRIMARY KEY,\n client_secret_hash TEXT,\n client_name TEXT,\n redirect_uris TEXT NOT NULL,\n grant_types TEXT NOT NULL,\n token_endpoint_auth_method TEXT NOT NULL DEFAULT 'none',\n scope TEXT,\n created_at TEXT NOT NULL,\n client_secret_expires_at INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS oauth_auth_codes (\n code_hash TEXT PRIMARY KEY,\n client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n redirect_uri TEXT NOT NULL,\n code_challenge TEXT NOT NULL,\n code_challenge_method TEXT NOT NULL,\n scope TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS oauth_tokens (\n token_hash TEXT PRIMARY KEY,\n token_type TEXT NOT NULL,\n client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n scope TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n`;\n\nexport interface CreateUserInput {\n email: string;\n name: string;\n password_hash: string | null;\n role: Role;\n provider?: Provider;\n external_id?: string | null;\n}\n\nexport interface UpdateUserInput {\n name?: string;\n role?: Role;\n password_hash?: string;\n provider?: Provider;\n external_id?: string | null;\n}\n\nfunction toSafeUser(user: LocalUser): SafeUser {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n role: user.role,\n provider: user.provider,\n attributes: user.attributes,\n created_at: user.created_at,\n updated_at: user.updated_at,\n };\n}\n\nexport class AuthDatabase {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.exec(SCHEMA_SQL);\n\n // Migrate: add attributes column if missing\n try {\n this.db.prepare(\"SELECT attributes FROM users LIMIT 0\").get();\n } catch {\n this.db.exec(\"ALTER TABLE users ADD COLUMN attributes TEXT NOT NULL DEFAULT '{}'\");\n }\n }\n\n close(): void {\n this.db.close();\n }\n\n needsSetup(): boolean {\n return this.getUserCount() === 0;\n }\n\n getUserCount(): number {\n const row = this.db.prepare('SELECT COUNT(*) as count FROM users').get() as { count: number };\n return row.count;\n }\n\n private getAdminCount(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as count FROM users WHERE role = 'admin'\").get() as { count: number };\n return row.count;\n }\n\n createUser(input: CreateUserInput): SafeUser {\n const id = uuidv4();\n const now = new Date().toISOString();\n\n this.db.prepare(`\n INSERT INTO users (id, email, name, password_hash, role, provider, external_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id,\n input.email,\n input.name,\n input.password_hash,\n input.role,\n input.provider ?? 'local',\n input.external_id ?? null,\n now,\n now,\n );\n\n return this.getUserById(id)! as SafeUser;\n }\n\n getUserById(id: string): LocalUser | null {\n return (this.db.prepare('SELECT * FROM users WHERE id = ?').get(id) as LocalUser) ?? null;\n }\n\n getUserByEmail(email: string): LocalUser | null {\n return (this.db.prepare('SELECT * FROM users WHERE email = ?').get(email) as LocalUser) ?? null;\n }\n\n listUsers(): SafeUser[] {\n const users = this.db.prepare('SELECT * FROM users ORDER BY created_at ASC').all() as LocalUser[];\n return users.map(toSafeUser);\n }\n\n updateUser(id: string, input: UpdateUserInput): void {\n // Guard: prevent changing last admin's role\n if (input.role && input.role !== 'admin') {\n const user = this.getUserById(id);\n if (user && user.role === 'admin' && this.getAdminCount() === 1) {\n throw new Error('Cannot change role of last admin user');\n }\n }\n\n const sets: string[] = [];\n const values: unknown[] = [];\n\n if (input.name !== undefined) { sets.push('name = ?'); values.push(input.name); }\n if (input.role !== undefined) { sets.push('role = ?'); values.push(input.role); }\n if (input.password_hash !== undefined) { sets.push('password_hash = ?'); values.push(input.password_hash); }\n if (input.provider !== undefined) { sets.push('provider = ?'); values.push(input.provider); }\n if (input.external_id !== undefined) { sets.push('external_id = ?'); values.push(input.external_id); }\n\n if (sets.length === 0) return;\n\n sets.push('updated_at = ?');\n values.push(new Date().toISOString());\n values.push(id);\n\n this.db.prepare(`UPDATE users SET ${sets.join(', ')} WHERE id = ?`).run(...values);\n }\n\n deleteUser(id: string): void {\n const user = this.getUserById(id);\n if (user && user.role === 'admin' && this.getAdminCount() === 1) {\n throw new Error('Cannot delete last admin user');\n }\n this.db.prepare('DELETE FROM users WHERE id = ?').run(id);\n }\n\n createSession(token: string, userId: string, ttlMs: number): void {\n const now = new Date();\n const expiresAt = new Date(now.getTime() + ttlMs);\n\n this.db.prepare(`\n INSERT INTO sessions (id, user_id, expires_at, created_at)\n VALUES (?, ?, ?, ?)\n `).run(token, userId, expiresAt.toISOString(), now.toISOString());\n }\n\n validateSession(token: string): Session | null {\n const session = this.db.prepare(\n 'SELECT * FROM sessions WHERE id = ? AND expires_at > ?'\n ).get(token, new Date().toISOString()) as Session | undefined;\n\n return session ?? null;\n }\n\n deleteSession(token: string): void {\n this.db.prepare('DELETE FROM sessions WHERE id = ?').run(token);\n }\n\n deleteUserSessions(userId: string): void {\n this.db.prepare('DELETE FROM sessions WHERE user_id = ?').run(userId);\n }\n\n purgeExpiredSessions(): number {\n const result = this.db.prepare(\n 'DELETE FROM sessions WHERE expires_at <= ?'\n ).run(new Date().toISOString());\n return result.changes;\n }\n\n getUserByProviderAndExternalId(provider: string, externalId: string): LocalUser | null {\n return (this.db.prepare(\n 'SELECT * FROM users WHERE provider = ? AND external_id = ?'\n ).get(provider, externalId) as LocalUser) ?? null;\n }\n\n // --- User Attributes ---\n\n getUserAttributes(id: string): Record<string, string> {\n const row = this.db.prepare('SELECT attributes FROM users WHERE id = ?').get(id) as { attributes: string } | undefined;\n if (!row) return {};\n try {\n return JSON.parse(row.attributes);\n } catch {\n return {};\n }\n }\n\n updateUserAttributes(id: string, attributes: Record<string, string>): void {\n this.db.prepare('UPDATE users SET attributes = ?, updated_at = ? WHERE id = ?')\n .run(JSON.stringify(attributes), new Date().toISOString(), id);\n }\n\n // --- Share Links ---\n\n createShareLink(input: CreateShareLinkInput): ShareLink {\n const id = uuidv4();\n const token = randomBytes(32).toString('hex');\n const now = new Date().toISOString();\n\n this.db.prepare(`\n INSERT INTO share_links (id, token, resource_type, resource_name, created_by, created_at, expires_at, is_active)\n VALUES (?, ?, ?, ?, ?, ?, ?, 1)\n `).run(id, token, input.resourceType, input.resourceName, input.createdBy, now, input.expiresAt ?? null);\n\n return this.db.prepare('SELECT * FROM share_links WHERE id = ?').get(id) as ShareLink;\n }\n\n getShareLinkByToken(token: string): ShareLink | null {\n const now = new Date().toISOString();\n const link = this.db.prepare(\n 'SELECT * FROM share_links WHERE token = ? AND is_active = 1 AND (expires_at IS NULL OR expires_at > ?)'\n ).get(token, now) as ShareLink | undefined;\n return link ?? null;\n }\n\n listShareLinks(createdBy?: string): ShareLink[] {\n if (createdBy) {\n return this.db.prepare(\n 'SELECT * FROM share_links WHERE created_by = ? AND is_active = 1 ORDER BY created_at DESC'\n ).all(createdBy) as ShareLink[];\n }\n return this.db.prepare(\n 'SELECT * FROM share_links WHERE is_active = 1 ORDER BY created_at DESC'\n ).all() as ShareLink[];\n }\n\n revokeShareLink(id: string): void {\n this.db.prepare('UPDATE share_links SET is_active = 0 WHERE id = ?').run(id);\n }\n\n deleteShareLink(id: string): void {\n this.db.prepare('DELETE FROM share_links WHERE id = ?').run(id);\n }\n\n // ---- OAuth: clients ----\n registerOAuthClient(input: RegisterOAuthClientInput): OAuthClient {\n const now = new Date().toISOString();\n this.db.prepare(`\n INSERT INTO oauth_clients\n (client_id, client_secret_hash, client_name, redirect_uris, grant_types,\n token_endpoint_auth_method, scope, created_at, client_secret_expires_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.client_id,\n input.client_secret_hash,\n input.client_name,\n JSON.stringify(input.redirect_uris),\n JSON.stringify(input.grant_types),\n input.token_endpoint_auth_method,\n input.scope,\n now,\n input.client_secret_expires_at,\n );\n return this.getOAuthClient(input.client_id)!;\n }\n\n getOAuthClient(clientId: string): OAuthClient | null {\n return (this.db.prepare('SELECT * FROM oauth_clients WHERE client_id = ?').get(clientId) as OAuthClient) ?? null;\n }\n\n // ---- OAuth: authorization codes (single-use) ----\n createAuthCode(input: CreateAuthCodeInput): void {\n this.db.prepare(`\n INSERT INTO oauth_auth_codes\n (code_hash, client_id, user_id, redirect_uri, code_challenge, code_challenge_method, scope, expires_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.code_hash, input.client_id, input.user_id, input.redirect_uri,\n input.code_challenge, input.code_challenge_method, input.scope,\n input.expires_at, new Date().toISOString(),\n );\n }\n\n /** Atomically fetch-and-delete a non-expired auth code. Returns null if missing/expired. */\n consumeAuthCode(codeHash: string): OAuthAuthCode | null {\n const tx = this.db.transaction((hash: string) => {\n const row = this.db.prepare(\n 'SELECT * FROM oauth_auth_codes WHERE code_hash = ?'\n ).get(hash) as OAuthAuthCode | undefined;\n this.db.prepare('DELETE FROM oauth_auth_codes WHERE code_hash = ?').run(hash);\n if (!row) return null;\n if (new Date(row.expires_at).getTime() <= Date.now()) return null;\n return row;\n });\n return tx(codeHash);\n }\n\n // ---- OAuth: tokens ----\n createOAuthToken(input: CreateOAuthTokenInput): void {\n this.db.prepare(`\n INSERT INTO oauth_tokens (token_hash, token_type, client_id, user_id, scope, expires_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.token_hash, input.token_type, input.client_id, input.user_id,\n input.scope, input.expires_at, new Date().toISOString(),\n );\n }\n\n getOAuthToken(tokenHash: string, type: OAuthTokenType): OAuthToken | null {\n const row = this.db.prepare(\n 'SELECT * FROM oauth_tokens WHERE token_hash = ? AND token_type = ? AND expires_at > ?'\n ).get(tokenHash, type, new Date().toISOString()) as OAuthToken | undefined;\n return row ?? null;\n }\n\n deleteOAuthToken(tokenHash: string): void {\n this.db.prepare('DELETE FROM oauth_tokens WHERE token_hash = ?').run(tokenHash);\n }\n\n purgeExpiredOAuth(): number {\n const now = new Date().toISOString();\n const codes = this.db.prepare('DELETE FROM oauth_auth_codes WHERE expires_at <= ?').run(now);\n const tokens = this.db.prepare('DELETE FROM oauth_tokens WHERE expires_at <= ?').run(now);\n return codes.changes + tokens.changes;\n }\n}\n","import { randomBytes } from 'crypto';\n\nexport function generateSessionToken(): string {\n return randomBytes(32).toString('hex');\n}\n\nconst DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\nexport function parseTtl(ttl: string): number {\n const match = ttl.match(/^(\\d+)(d|h|m)$/);\n if (!match || !match[1] || !match[2]) return DEFAULT_TTL_MS;\n\n const value = parseInt(match[1], 10);\n switch (match[2]) {\n case 'd': return value * 24 * 60 * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'm': return value * 60 * 1000;\n default: return DEFAULT_TTL_MS;\n }\n}\n","import { randomBytes, createHash } from 'node:crypto';\n\n/** A 256-bit opaque token, hex-encoded. */\nexport function generateOpaqueToken(): string {\n return randomBytes(32).toString('hex');\n}\n\n/** SHA-256 of a token, hex — what we store at rest so a DB leak yields no usable tokens. */\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n}\n"],"mappings":"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","names":["randomBytes","randomBytes"]}
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
hashToken,
|
|
37
37
|
parseTtl,
|
|
38
38
|
verifyPassword
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-DZVT6PHW.js";
|
|
40
40
|
import {
|
|
41
41
|
BigQueryConnector,
|
|
42
42
|
DuckDBConnector,
|
|
@@ -20842,20 +20842,20 @@ async function authAdminRoutes(fastify, options) {
|
|
|
20842
20842
|
});
|
|
20843
20843
|
fastify.post("/api/auth/users", async (request, reply) => {
|
|
20844
20844
|
const { email, name, password, role } = request.body;
|
|
20845
|
-
if (!email || !name || !
|
|
20846
|
-
return reply.status(400).send({ error: "Email, name,
|
|
20845
|
+
if (!email || !name || !role) {
|
|
20846
|
+
return reply.status(400).send({ error: "Email, name, and role are required" });
|
|
20847
20847
|
}
|
|
20848
20848
|
if (!["admin", "editor", "viewer"].includes(role)) {
|
|
20849
20849
|
return reply.status(400).send({ error: "Role must be admin, editor, or viewer" });
|
|
20850
20850
|
}
|
|
20851
|
-
if (password.length < 8) {
|
|
20851
|
+
if (password && password.length < 8) {
|
|
20852
20852
|
return reply.status(400).send({ error: "Password must be at least 8 characters" });
|
|
20853
20853
|
}
|
|
20854
20854
|
const existing = authDb.getUserByEmail(email);
|
|
20855
20855
|
if (existing) {
|
|
20856
20856
|
return reply.status(409).send({ error: "A user with this email already exists" });
|
|
20857
20857
|
}
|
|
20858
|
-
const passwordHash = await hashPassword(password);
|
|
20858
|
+
const passwordHash = password ? await hashPassword(password) : null;
|
|
20859
20859
|
const user = authDb.createUser({ email, name, password_hash: passwordHash, role });
|
|
20860
20860
|
return reply.status(201).send({ user });
|
|
20861
20861
|
});
|
|
@@ -21016,6 +21016,21 @@ async function authSSORoutes(fastify, options) {
|
|
|
21016
21016
|
}
|
|
21017
21017
|
const existingByEmail = authDb.getUserByEmail(email);
|
|
21018
21018
|
if (existingByEmail) {
|
|
21019
|
+
const isInvite = existingByEmail.password_hash === null && (existingByEmail.provider === "local" || existingByEmail.provider === provider) && !existingByEmail.external_id;
|
|
21020
|
+
if (isInvite) {
|
|
21021
|
+
authDb.updateUser(existingByEmail.id, {
|
|
21022
|
+
provider,
|
|
21023
|
+
external_id: externalId,
|
|
21024
|
+
name
|
|
21025
|
+
});
|
|
21026
|
+
const token2 = generateSessionToken();
|
|
21027
|
+
authDb.createSession(token2, existingByEmail.id, sessionTtlMs);
|
|
21028
|
+
reply.setCookie("yamchart_session", token2, cookieOptions);
|
|
21029
|
+
const ret2 = sanitizeReturnTo(request.cookies?.yamchart_sso_return);
|
|
21030
|
+
if (ret2)
|
|
21031
|
+
reply.clearCookie("yamchart_sso_return", { path: "/" });
|
|
21032
|
+
return reply.redirect(ret2 ?? "/#/");
|
|
21033
|
+
}
|
|
21019
21034
|
return reply.redirect("/#/login?error=account_conflict");
|
|
21020
21035
|
}
|
|
21021
21036
|
const { allowed, role } = resolveSsoProvisioning(email, config);
|
|
@@ -29934,4 +29949,4 @@ async function runDevServer(projectDir, options) {
|
|
|
29934
29949
|
export {
|
|
29935
29950
|
runDevServer
|
|
29936
29951
|
};
|
|
29937
|
-
//# sourceMappingURL=dev-
|
|
29952
|
+
//# sourceMappingURL=dev-GWXHBBWB.js.map
|