fix server session
This commit is contained in:
parent
e618c883d5
commit
c500728f08
|
|
@ -13,8 +13,7 @@ export type ServerContext = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface SessionContext<T extends SessionData<any>>
|
export interface SessionContext<T> extends ServerContext {
|
||||||
extends ServerContext {
|
|
||||||
session: ServerSession<T>;
|
session: ServerSession<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,7 +91,10 @@ export const useServerRouter = <T extends ReturnType<typeof newServerRouter>>(
|
||||||
if (route.opt && route.opt?.request_as === "raw") {
|
if (route.opt && route.opt?.request_as === "raw") {
|
||||||
result = await route.handler.default.bind(arg)();
|
result = await route.handler.default.bind(arg)();
|
||||||
} else {
|
} else {
|
||||||
const params = await req.json();
|
let params = [];
|
||||||
|
try {
|
||||||
|
params = await req.json();
|
||||||
|
} catch (e) {}
|
||||||
result = await route.handler.default.bind(arg)(...params);
|
result = await route.handler.default.bind(arg)(...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
SingleSession,
|
SingleSession,
|
||||||
} from "./session/session-store";
|
} from "./session/session-store";
|
||||||
|
|
||||||
export type ServerSession<T extends SessionData<any>> = SessionStore<T> & {
|
export type ServerSession<T> = SessionStore<T> & {
|
||||||
current?: SingleSession<T>;
|
current?: SingleSession<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -17,11 +17,12 @@ type SessionServerHandler = {
|
||||||
handle: (arg: ServerContext) => Promise<Response>;
|
handle: (arg: ServerContext) => Promise<Response>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createSessionServer = <T extends SessionData<any>>(arg: {
|
export const createSessionServer = <T >(arg: {
|
||||||
encrypt?: boolean;
|
encrypt?: boolean;
|
||||||
router?: ReturnType<typeof useServerRouter>;
|
router?: ReturnType<typeof useServerRouter>;
|
||||||
|
site_id?: string;
|
||||||
}): SessionServerHandler => {
|
}): SessionServerHandler => {
|
||||||
const server_session = newSessionStore<T>();
|
const server_session = newSessionStore<T>(arg.site_id);
|
||||||
|
|
||||||
const server_handler: SessionServerHandler = {
|
const server_handler: SessionServerHandler = {
|
||||||
async cleanup() {},
|
async cleanup() {},
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,16 @@ import { select } from "lib/preset/login/utils/select";
|
||||||
export const session = sqliteTable(
|
export const session = sqliteTable(
|
||||||
"session",
|
"session",
|
||||||
{
|
{
|
||||||
session_id: text("session_id")
|
sid: text("sid")
|
||||||
.notNull()
|
.notNull()
|
||||||
.primaryKey()
|
.primaryKey()
|
||||||
.$defaultFn(() => createId()),
|
.$defaultFn(() => createId()),
|
||||||
|
uid: text("uid").notNull(),
|
||||||
created_at: integer("created_at", { mode: "timestamp_ms" }).default(
|
created_at: integer("created_at", { mode: "timestamp_ms" }).default(
|
||||||
new Date()
|
new Date()
|
||||||
),
|
),
|
||||||
active: integer("active", { mode: "boolean" }),
|
active: integer("active", { mode: "boolean" }),
|
||||||
data: text("data", { mode: "json" }),
|
data: text("data", { mode: "json" }).notNull(),
|
||||||
expired_at: integer("expired_at", { mode: "timestamp_ms" }),
|
expired_at: integer("expired_at", { mode: "timestamp_ms" }),
|
||||||
},
|
},
|
||||||
(table) => {
|
(table) => {
|
||||||
|
|
@ -26,7 +27,7 @@ export const session = sqliteTable(
|
||||||
export const track = sqliteTable(
|
export const track = sqliteTable(
|
||||||
"track",
|
"track",
|
||||||
{
|
{
|
||||||
track_id: text("track_id")
|
id: text("id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.primaryKey()
|
.primaryKey()
|
||||||
.$defaultFn(() => createId()),
|
.$defaultFn(() => createId()),
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,153 @@
|
||||||
export type NewSessionData<T extends Record<string, any>> = T & {
|
/// <reference types="bun-types" />
|
||||||
|
import Database from "bun:sqlite";
|
||||||
|
import { dir } from "../utils/dir";
|
||||||
|
import { mkdirSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
import { BunSQLiteDatabase, drizzle } from "drizzle-orm/bun-sqlite";
|
||||||
|
import { session } from "./schema";
|
||||||
|
import { and, eq, sql } from "drizzle-orm";
|
||||||
|
|
||||||
|
export interface NewSessionData<T> {
|
||||||
uid: string;
|
uid: string;
|
||||||
role: string;
|
role: string;
|
||||||
|
data?: T;
|
||||||
expired_at?: number;
|
expired_at?: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type SessionData<T extends Record<string, any>> = NewSessionData<T> & {
|
export interface SessionData<T> extends NewSessionData<T> {
|
||||||
sid: string;
|
sid: string;
|
||||||
|
active: boolean;
|
||||||
created_at: number;
|
created_at: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type SingleSession<T extends SessionData<any>> = {
|
export interface SingleSession<T> extends SessionData<T> {
|
||||||
data: T;
|
track: (arg: { path: string }) => void;
|
||||||
track: (arg: { path: string }) => Promise<void>;
|
destroy: () => boolean;
|
||||||
destroy: () => Promise<void>;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
type FilterSessionArg = {
|
type FilterSessionArg = {
|
||||||
uid: string;
|
uid: string;
|
||||||
sid: string;
|
sid: string;
|
||||||
role: string;
|
role: string;
|
||||||
|
active: boolean;
|
||||||
created_at: { gt?: number; lt?: number };
|
created_at: { gt?: number; lt?: number };
|
||||||
expired_at: { gt?: number; lt?: number };
|
expired_at: { gt?: number; lt?: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SessionStore<T extends SessionData<any>> = {
|
export type SessionStore<T> = {
|
||||||
create: (
|
create: (arg: {
|
||||||
data: Record<string, any> & {
|
uid: string;
|
||||||
uid: string;
|
role: string;
|
||||||
role: string;
|
data?: T;
|
||||||
expired_at?: number;
|
expired_at?: number;
|
||||||
}
|
}) => SingleSession<T>;
|
||||||
) => Promise<SingleSession<T>>;
|
findMany: (arg?: Partial<FilterSessionArg>) => SingleSession<T>[];
|
||||||
findMany: (arg: Partial<FilterSessionArg>) => Promise<SingleSession<T>[]>;
|
findFirst: (arg?: Partial<FilterSessionArg>) => null | SingleSession<T>;
|
||||||
findFirst: (
|
|
||||||
arg: Partial<FilterSessionArg>
|
|
||||||
) => Promise<null | SingleSession<T>>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newSessionStore = <T>() => {
|
export const newSessionStore = <T>(site_id?: string) => {
|
||||||
|
const db_path = site_id
|
||||||
|
? dir.data(`/code/${site_id}/site/sqlite`)
|
||||||
|
: dir.data(`/sqlite`);
|
||||||
|
|
||||||
|
mkdirSync(db_path, { recursive: true });
|
||||||
|
|
||||||
|
const path = { session: join(db_path, "session.db") };
|
||||||
|
const db = {
|
||||||
|
session: drizzle(new Database(path.session), { schema: { session } }),
|
||||||
|
track: {} as Record<string, BunSQLiteDatabase<Record<string, never>>>,
|
||||||
|
};
|
||||||
|
|
||||||
|
db.session.run(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS session (
|
||||||
|
sid text PRIMARY KEY NOT NULL,
|
||||||
|
uid text NOT NULL,
|
||||||
|
created_at integer NOT NULL DEFAULT current_timestamp,
|
||||||
|
active integer,
|
||||||
|
data text NOT NULL,
|
||||||
|
expired_at integer
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS expired_at_idx ON session (expired_at);
|
||||||
|
`);
|
||||||
|
|
||||||
|
// const track_ddl = sql`
|
||||||
|
// CREATE TABLE track (
|
||||||
|
// id text PRIMARY KEY NOT NULL,
|
||||||
|
// created_at integer DEFAULT current_timestamp,
|
||||||
|
// session_id text,
|
||||||
|
// url text NOT NULL,
|
||||||
|
// referer text,
|
||||||
|
// user_ip text,
|
||||||
|
// data text,
|
||||||
|
// tstamp integer DEFAULT current_timestamp
|
||||||
|
// );
|
||||||
|
// CREATE INDEX session_id ON track (session_id);`;
|
||||||
|
|
||||||
|
const createSingleStore = <E extends SessionData<T>>(data: any) => {
|
||||||
|
if (!data) return null;
|
||||||
|
|
||||||
|
const row: SingleSession<E> = {
|
||||||
|
...data,
|
||||||
|
destroy() {
|
||||||
|
try {
|
||||||
|
db.session.delete(session).where(eq(session.sid, row.sid)).run();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
track(arg) {},
|
||||||
|
};
|
||||||
|
|
||||||
|
return row;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async create(data) {
|
create(data) {
|
||||||
const new_session: SingleSession<T> = {
|
return createSingleStore(
|
||||||
data: { ...data, created_at: Date.now() } as T,
|
db.session
|
||||||
async destroy() {},
|
.insert(session)
|
||||||
async track(arg) {},
|
.values({
|
||||||
};
|
uid: data.uid,
|
||||||
return new_session;
|
data,
|
||||||
|
active: true,
|
||||||
|
expired_at: data.expired_at
|
||||||
|
? new Date(data.expired_at * 1000)
|
||||||
|
: undefined,
|
||||||
|
})
|
||||||
|
.returning()
|
||||||
|
.get()
|
||||||
|
);
|
||||||
},
|
},
|
||||||
async findFirst(arg) {
|
findFirst(arg) {
|
||||||
return null;
|
return createSingleStore(
|
||||||
|
db.session
|
||||||
|
.select()
|
||||||
|
.from(session)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
...Object.entries(arg || {}).map(([k, v]) => {
|
||||||
|
return eq((session as any)[k], v);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.get()
|
||||||
|
);
|
||||||
},
|
},
|
||||||
async findMany(arg) {
|
findMany(arg) {
|
||||||
return [];
|
return db.session
|
||||||
|
.select()
|
||||||
|
.from(session)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
...Object.entries(arg || {}).map(([k, v]) => {
|
||||||
|
return eq((session as any)[k], v);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.all()
|
||||||
|
.map((e) => createSingleStore(e));
|
||||||
},
|
},
|
||||||
} as SessionStore<T>;
|
} as SessionStore<T>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const g = (typeof global !== "undefined" ? global : undefined) as unknown as {
|
||||||
|
datadir?: string;
|
||||||
|
mode?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dir = {
|
||||||
|
data: (path: string) => {
|
||||||
|
const final_path = path
|
||||||
|
.split("/")
|
||||||
|
.filter((e) => e !== "..")
|
||||||
|
.join("/");
|
||||||
|
if (g.mode === "prod") return join(process.cwd(), "..", "data", final_path);
|
||||||
|
else return join(process.cwd(), "data", final_path);
|
||||||
|
},
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue