lint
This commit is contained in:
parent
ed4ea1db40
commit
b9f36b5c2c
12 changed files with 160 additions and 131 deletions
|
@ -1,4 +1,8 @@
|
||||||
import globals from "globals";
|
import globals from "globals";
|
||||||
import pluginJs from "@eslint/js";
|
import pluginJs from "@eslint/js";
|
||||||
|
|
||||||
export default [{ languageOptions: { globals: globals.node } }, pluginJs.configs.recommended];
|
export default [
|
||||||
|
{ ignores: ["**/dist/*"] },
|
||||||
|
{ languageOptions: { globals: globals.node } },
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
];
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "tsc && node dist/index.js",
|
"start": "tsc && node dist/index.js",
|
||||||
"lint:fix": "eslint --fix && prettier . --write",
|
"lint:fix": "eslint . --fix && prettier . --write",
|
||||||
"lint": "eslint && prettier . --check"
|
"lint": "eslint . && prettier . --check"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.5.0",
|
"@eslint/js": "^9.5.0",
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Fastify from "fastify";
|
||||||
|
|
||||||
let app = Fastify({
|
let app = Fastify({
|
||||||
logger: true,
|
logger: true,
|
||||||
}).withTypeProvider<TypeBoxTypeProvider>()
|
}).withTypeProvider<TypeBoxTypeProvider>();
|
||||||
|
|
||||||
export type AppInterface = typeof app;
|
export type AppInterface = typeof app;
|
||||||
export default app;
|
export default app;
|
||||||
|
|
|
@ -20,36 +20,35 @@ import * as Jose from "jose";
|
||||||
import { JWT_ALG, JWT_SECRET } from "./consts.js";
|
import { JWT_ALG, JWT_SECRET } from "./consts.js";
|
||||||
import { DatabaseInterface, toDBList } from "./database.js";
|
import { DatabaseInterface, toDBList } from "./database.js";
|
||||||
|
|
||||||
|
|
||||||
export type AuthInterface = Awaited<ReturnType<typeof startAuth>>;
|
export type AuthInterface = Awaited<ReturnType<typeof startAuth>>;
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
id: string,
|
id: string;
|
||||||
createdAt: number,
|
createdAt: number;
|
||||||
lastConnected: number,
|
lastConnected: number;
|
||||||
name: string,
|
name: string;
|
||||||
email: string,
|
email: string;
|
||||||
password: string,
|
password: string;
|
||||||
limitID: string,
|
limitID: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type NewUser = {
|
export type NewUser = {
|
||||||
name: string,
|
name: string;
|
||||||
email: string,
|
email: string;
|
||||||
password: string,
|
password: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type UpdateUser = {
|
export type UpdateUser = {
|
||||||
name?: string,
|
name?: string;
|
||||||
email?: string,
|
email?: string;
|
||||||
password?: string,
|
password?: string;
|
||||||
assets?: string[],
|
assets?: string[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function startAuth(database: DatabaseInterface) {
|
export async function startAuth(database: DatabaseInterface) {
|
||||||
let funcs = {
|
let funcs = {
|
||||||
user: async (uid: string) => await database.user(uid) satisfies User,
|
user: async (uid: string) => (await database.user(uid)) satisfies User,
|
||||||
findUserByEmail: async (email: string) => await database.findUserByEmail(email) satisfies User,
|
findUserByEmail: async (email: string) => (await database.findUserByEmail(email)) satisfies User,
|
||||||
findUserBySessionKey: async (sessionKey: string) => {
|
findUserBySessionKey: async (sessionKey: string) => {
|
||||||
let key = await database.sessionKey(sessionKey);
|
let key = await database.sessionKey(sessionKey);
|
||||||
return await database.user(key.userID);
|
return await database.user(key.userID);
|
||||||
|
@ -61,7 +60,8 @@ export async function startAuth(database: DatabaseInterface) {
|
||||||
return await database.updateUser(uid, user);
|
return await database.updateUser(uid, user);
|
||||||
},
|
},
|
||||||
addUser: async (user: NewUser) => {
|
addUser: async (user: NewUser) => {
|
||||||
let result = await database.insertUser({
|
let result = await database.insertUser(
|
||||||
|
{
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
lastConnected: Date.now(),
|
lastConnected: Date.now(),
|
||||||
|
@ -71,11 +71,13 @@ export async function startAuth(database: DatabaseInterface) {
|
||||||
assets: toDBList([]),
|
assets: toDBList([]),
|
||||||
// FIXME: This shouldn't be required, the DB interface overwrites it.
|
// FIXME: This shouldn't be required, the DB interface overwrites it.
|
||||||
limitID: "",
|
limitID: "",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
currentAssetCount: 0,
|
currentAssetCount: 0,
|
||||||
maxAssetCount: 5,
|
maxAssetCount: 5,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return result satisfies User;
|
return result satisfies User;
|
||||||
},
|
},
|
||||||
|
@ -103,9 +105,9 @@ export async function startAuth(database: DatabaseInterface) {
|
||||||
},
|
},
|
||||||
verifyJwt: async (jwt) => {
|
verifyJwt: async (jwt) => {
|
||||||
return await Jose.jwtVerify<{
|
return await Jose.jwtVerify<{
|
||||||
uid: string,
|
uid: string;
|
||||||
email: string,
|
email: string;
|
||||||
name: string,
|
name: string;
|
||||||
}>(jwt, JWT_SECRET);
|
}>(jwt, JWT_SECRET);
|
||||||
},
|
},
|
||||||
cleanUser: (user: User) => {
|
cleanUser: (user: User) => {
|
||||||
|
@ -114,7 +116,7 @@ export async function startAuth(database: DatabaseInterface) {
|
||||||
clean.limitID = undefined;
|
clean.limitID = undefined;
|
||||||
|
|
||||||
return clean;
|
return clean;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return funcs;
|
return funcs;
|
||||||
|
|
|
@ -21,14 +21,14 @@ import { sqliteTable } from "drizzle-orm/sqlite-core";
|
||||||
import { text, integer } from "drizzle-orm/sqlite-core";
|
import { text, integer } from "drizzle-orm/sqlite-core";
|
||||||
import { asc, desc, eq, sql } from "drizzle-orm";
|
import { asc, desc, eq, sql } from "drizzle-orm";
|
||||||
|
|
||||||
export type DatabaseInterface = Awaited<ReturnType<typeof startDatabase>>
|
export type DatabaseInterface = Awaited<ReturnType<typeof startDatabase>>;
|
||||||
|
|
||||||
export function toDBList(input: any[]): string {
|
export function toDBList(input: any[]): string {
|
||||||
return JSON.stringify(input);
|
return JSON.stringify(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fromDBList<T>(input: string): Array<T> {
|
export function fromDBList<T>(input: string): Array<T> {
|
||||||
return JSON.parse(input)
|
return JSON.parse(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startDatabase() {
|
export async function startDatabase() {
|
||||||
|
@ -134,11 +134,14 @@ export async function startDatabase() {
|
||||||
let result = await database.select().from(limits).where(eq(limits.id, limitsID));
|
let result = await database.select().from(limits).where(eq(limits.id, limitsID));
|
||||||
return result[0];
|
return result[0];
|
||||||
},
|
},
|
||||||
updateUser: async (userID: string, newUser: {
|
updateUser: async (
|
||||||
name?: string,
|
userID: string,
|
||||||
email?: string,
|
newUser: {
|
||||||
password?: string,
|
name?: string;
|
||||||
}) => {
|
email?: string;
|
||||||
|
password?: string;
|
||||||
|
},
|
||||||
|
) => {
|
||||||
let result = await database.update(users).set(newUser).where(eq(users.id, userID)).returning();
|
let result = await database.update(users).set(newUser).where(eq(users.id, userID)).returning();
|
||||||
return result[0];
|
return result[0];
|
||||||
},
|
},
|
||||||
|
@ -157,7 +160,12 @@ export async function startDatabase() {
|
||||||
findSessionKeyByUserID: async (userID: string) => {
|
findSessionKeyByUserID: async (userID: string) => {
|
||||||
return await database.select().from(session_keys).where(eq(session_keys.userID, userID));
|
return await database.select().from(session_keys).where(eq(session_keys.userID, userID));
|
||||||
},
|
},
|
||||||
insertEntry: async (entry: typeof entries.$inferInsert, musicEntry?: typeof musicEntries.$inferInsert, locationEntry?: typeof locationEntries.$inferInsert, dateEntry?: typeof dateEntries.$inferInsert) => {
|
insertEntry: async (
|
||||||
|
entry: typeof entries.$inferInsert,
|
||||||
|
musicEntry?: typeof musicEntries.$inferInsert,
|
||||||
|
locationEntry?: typeof locationEntries.$inferInsert,
|
||||||
|
dateEntry?: typeof dateEntries.$inferInsert,
|
||||||
|
) => {
|
||||||
if (entry.kind === "album" || entry.kind === "song") {
|
if (entry.kind === "album" || entry.kind === "song") {
|
||||||
let result = await database.insert(musicEntries).values(musicEntry).returning({ id: musicEntries.id });
|
let result = await database.insert(musicEntries).values(musicEntry).returning({ id: musicEntries.id });
|
||||||
entry.musicEntry = result[0].id;
|
entry.musicEntry = result[0].id;
|
||||||
|
@ -188,12 +196,16 @@ export async function startDatabase() {
|
||||||
.orderBy(desc(entries.createdAt));
|
.orderBy(desc(entries.createdAt));
|
||||||
|
|
||||||
for (let key in result) {
|
for (let key in result) {
|
||||||
if (!result.hasOwnProperty(key)) { continue; }
|
if (!result.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let entry = structuredClone(result[key]);
|
let entry = structuredClone(result[key]);
|
||||||
let base = {};
|
let base = {};
|
||||||
if (entry.musicEntry != null) {
|
if (entry.musicEntry != null) {
|
||||||
let musicDetails = (await database.select().from(musicEntries).where(eq(musicEntries.id, entry.musicEntry)))[0];
|
let musicDetails = (
|
||||||
|
await database.select().from(musicEntries).where(eq(musicEntries.id, entry.musicEntry))
|
||||||
|
)[0];
|
||||||
(musicDetails["link"] as any) = fromDBList(musicDetails.links);
|
(musicDetails["link"] as any) = fromDBList(musicDetails.links);
|
||||||
(musicDetails["id"] as any) = fromDBList(musicDetails.universalIDs);
|
(musicDetails["id"] as any) = fromDBList(musicDetails.universalIDs);
|
||||||
|
|
||||||
|
@ -201,22 +213,26 @@ export async function startDatabase() {
|
||||||
musicDetails["universalIDs"] = undefined;
|
musicDetails["universalIDs"] = undefined;
|
||||||
base = musicDetails;
|
base = musicDetails;
|
||||||
} else if (entry.locationEntry != null) {
|
} else if (entry.locationEntry != null) {
|
||||||
let locationDetails = (await database.select().from(locationEntries).where(eq(locationEntries.id, entry.locationEntry)))[0];
|
let locationDetails = (
|
||||||
|
await database.select().from(locationEntries).where(eq(locationEntries.id, entry.locationEntry))
|
||||||
|
)[0];
|
||||||
|
|
||||||
if (locationDetails.locationCoordinates != null) {
|
if (locationDetails.locationCoordinates != null) {
|
||||||
base = { location: JSON.parse(locationDetails.locationCoordinates) }
|
base = { location: JSON.parse(locationDetails.locationCoordinates) };
|
||||||
} else if (locationDetails.locationText != null) {
|
} else if (locationDetails.locationText != null) {
|
||||||
base = { location: locationDetails.locationText }
|
base = { location: locationDetails.locationText };
|
||||||
}
|
}
|
||||||
} else if (entry.dateEntry != null) {
|
} else if (entry.dateEntry != null) {
|
||||||
let dateDetails = (await database.select().from(dateEntries).where(eq(dateEntries.id, entry.dateEntry)))[0];
|
let dateDetails = (
|
||||||
|
await database.select().from(dateEntries).where(eq(dateEntries.id, entry.dateEntry))
|
||||||
|
)[0];
|
||||||
|
|
||||||
base = {
|
base = {
|
||||||
referencedDate: new Date(dateDetails["referencedDate"]).toISOString()
|
referencedDate: new Date(dateDetails["referencedDate"]).toISOString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
base["kind"] = entry.kind
|
base["kind"] = entry.kind;
|
||||||
|
|
||||||
result[key]["creationDate"] = new Date(entry.createdAt).toISOString();
|
result[key]["creationDate"] = new Date(entry.createdAt).toISOString();
|
||||||
(result[key] as any)["feelings"] = fromDBList(entry.feelings);
|
(result[key] as any)["feelings"] = fromDBList(entry.feelings);
|
||||||
|
|
|
@ -24,7 +24,7 @@ const Body = Type.Object({
|
||||||
contactMethod: Type.String(),
|
contactMethod: Type.String(),
|
||||||
name: Type.String(),
|
name: Type.String(),
|
||||||
value: Type.String(),
|
value: Type.String(),
|
||||||
})
|
});
|
||||||
|
|
||||||
type BodyType = Static<typeof Body>;
|
type BodyType = Static<typeof Body>;
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
||||||
});
|
});
|
||||||
|
|
||||||
return (await database.listHeirs(payload.uid))
|
return (await database.listHeirs(payload.uid))
|
||||||
.map(v => v["contactMethod"] = "email")
|
.map((v) => (v["contactMethod"] = "email"))
|
||||||
.map(v => v["value"] = v["email"])
|
.map((v) => (v["value"] = v["email"]))
|
||||||
.map(v => v["email"] = undefined);
|
.map((v) => (v["email"] = undefined));
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: { $ref: "schema://identity/authorization" },
|
headers: { $ref: "schema://identity/authorization" },
|
||||||
|
@ -76,9 +76,9 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
||||||
await database.removeHeir(request.body);
|
await database.removeHeir(request.body);
|
||||||
|
|
||||||
return (await database.listHeirs(payload.uid))
|
return (await database.listHeirs(payload.uid))
|
||||||
.map(v => v["contactMethod"] = "email")
|
.map((v) => (v["contactMethod"] = "email"))
|
||||||
.map(v => v["value"] = v["email"])
|
.map((v) => (v["value"] = v["email"]))
|
||||||
.map(v => v["email"] = undefined);
|
.map((v) => (v["email"] = undefined));
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: { $ref: "schema://identity/authorization" },
|
headers: { $ref: "schema://identity/authorization" },
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { Static, Type } from "@sinclair/typebox";
|
||||||
|
|
||||||
const EntryIDQuery = Type.Object({
|
const EntryIDQuery = Type.Object({
|
||||||
entry_id: Type.String(),
|
entry_id: Type.String(),
|
||||||
})
|
});
|
||||||
|
|
||||||
type EntryIDQueryType = Static<typeof EntryIDQuery>;
|
type EntryIDQueryType = Static<typeof EntryIDQuery>;
|
||||||
|
|
||||||
|
@ -43,22 +43,23 @@ const PutEntryBody = Type.Object({
|
||||||
backgroundColor: Type.String(),
|
backgroundColor: Type.String(),
|
||||||
textColor: Type.String(),
|
textColor: Type.String(),
|
||||||
}),
|
}),
|
||||||
])
|
]),
|
||||||
),
|
),
|
||||||
base: Type.Union([
|
base: Type.Union([
|
||||||
Type.Object({
|
Type.Object({
|
||||||
kind: Type.String(),
|
kind: Type.String(),
|
||||||
|
|
||||||
}),
|
}),
|
||||||
Type.Object({
|
Type.Object({
|
||||||
kind: Type.String(),
|
kind: Type.String(),
|
||||||
artist: Type.String(),
|
artist: Type.String(),
|
||||||
title: Type.String(),
|
title: Type.String(),
|
||||||
link: Type.Array(Type.String()),
|
link: Type.Array(Type.String()),
|
||||||
id: Type.Array(Type.Object({
|
id: Type.Array(
|
||||||
|
Type.Object({
|
||||||
provider: Type.String(),
|
provider: Type.String(),
|
||||||
id: Type.String(),
|
id: Type.String(),
|
||||||
})),
|
}),
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
Type.Object({
|
Type.Object({
|
||||||
kind: Type.String(),
|
kind: Type.String(),
|
||||||
|
@ -75,7 +76,7 @@ const PutEntryBody = Type.Object({
|
||||||
referencedDate: Type.String(),
|
referencedDate: Type.String(),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
type PutEntryBodyType = Static<typeof PutEntryBody>;
|
type PutEntryBodyType = Static<typeof PutEntryBody>;
|
||||||
|
@ -105,28 +106,30 @@ export default function registerRoutes(app: AppInterface, auth: AuthInterface, d
|
||||||
let entry = request.body.entry;
|
let entry = request.body.entry;
|
||||||
|
|
||||||
let musicEntry, locationEntry, dateEntry;
|
let musicEntry, locationEntry, dateEntry;
|
||||||
if ((entry.base.kind === "album" || entry.base.kind === "song") && 'artist' in entry.base) {
|
if ((entry.base.kind === "album" || entry.base.kind === "song") && "artist" in entry.base) {
|
||||||
musicEntry = {
|
musicEntry = {
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
title: entry.base.title,
|
title: entry.base.title,
|
||||||
artist: entry.base.artist,
|
artist: entry.base.artist,
|
||||||
links: toDBList(entry.base.link),
|
links: toDBList(entry.base.link),
|
||||||
universalIDs: toDBList(entry.base.id),
|
universalIDs: toDBList(entry.base.id),
|
||||||
}
|
};
|
||||||
} else if (entry.base.kind === "environment" && 'location' in entry.base) {
|
} else if (entry.base.kind === "environment" && "location" in entry.base) {
|
||||||
locationEntry = {
|
locationEntry = {
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
locationText: typeof entry.base.location === "string" ? entry.base.location : undefined,
|
locationText: typeof entry.base.location === "string" ? entry.base.location : undefined,
|
||||||
locationCoordinates: typeof entry.base.location === "string" ? undefined : JSON.stringify(entry.base.location),
|
locationCoordinates:
|
||||||
}
|
typeof entry.base.location === "string" ? undefined : JSON.stringify(entry.base.location),
|
||||||
} else if (entry.base.kind === "date" && 'referencedDate' in entry.base) {
|
};
|
||||||
|
} else if (entry.base.kind === "date" && "referencedDate" in entry.base) {
|
||||||
dateEntry = {
|
dateEntry = {
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
referencedDate: Date.parse(entry.base.referencedDate),
|
referencedDate: Date.parse(entry.base.referencedDate),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await database.insertEntry({
|
await database.insertEntry(
|
||||||
|
{
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
userID: payload.uid,
|
userID: payload.uid,
|
||||||
feelings: toDBList(entry.feelings),
|
feelings: toDBList(entry.feelings),
|
||||||
|
@ -135,7 +138,11 @@ export default function registerRoutes(app: AppInterface, auth: AuthInterface, d
|
||||||
description: entry.description,
|
description: entry.description,
|
||||||
kind: entry.base.kind,
|
kind: entry.base.kind,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
}, musicEntry, locationEntry, dateEntry);
|
},
|
||||||
|
musicEntry,
|
||||||
|
locationEntry,
|
||||||
|
dateEntry,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: { $ref: "schema://identity/authorization" },
|
headers: { $ref: "schema://identity/authorization" },
|
||||||
|
|
|
@ -22,7 +22,7 @@ import type { DatabaseInterface } from "../../database.js";
|
||||||
const Query = Type.Object({
|
const Query = Type.Object({
|
||||||
limit: Type.Number(),
|
limit: Type.Number(),
|
||||||
offset: Type.Number(),
|
offset: Type.Number(),
|
||||||
})
|
});
|
||||||
|
|
||||||
type QueryType = Static<typeof Query>;
|
type QueryType = Static<typeof Query>;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
||||||
let jwt = request.headers["authorization"].replace("Bearer", "").trim();
|
let jwt = request.headers["authorization"].replace("Bearer", "").trim();
|
||||||
let { payload } = await auth.verifyJwt(jwt);
|
let { payload } = await auth.verifyJwt(jwt);
|
||||||
|
|
||||||
return await database.entryPage(payload.uid, request.query.offset, request.query.limit)
|
return await database.entryPage(payload.uid, request.query.offset, request.query.limit);
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: { $ref: "schema://identity/authorization" },
|
headers: { $ref: "schema://identity/authorization" },
|
||||||
|
|
Loading…
Reference in a new issue