hoàn thành tích hợp FSRS
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import { IsEnum, IsUUID } from 'class-validator';
|
||||
|
||||
export enum ReviewQuality {
|
||||
BLACKOUT = 0,
|
||||
WRONG = 1,
|
||||
HARD = 2,
|
||||
GOOD = 3,
|
||||
EASY = 4,
|
||||
PERFECT = 5,
|
||||
}
|
||||
|
||||
export class PageReviewDto {
|
||||
@IsUUID()
|
||||
pageId: string;
|
||||
|
||||
@IsEnum(ReviewQuality)
|
||||
quality: ReviewQuality;
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
PageIdDto,
|
||||
PageInfoDto,
|
||||
} from './dto/page.dto';
|
||||
import { PageReviewDto } from './dto/page-review.dto';
|
||||
import { PageHistoryService } from './services/page-history.service';
|
||||
import { AuthUser } from '../../common/decorators/auth-user.decorator';
|
||||
import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
|
||||
@@ -647,4 +648,38 @@ export class PageController {
|
||||
|
||||
return this.pageService.getPageBreadCrumbs(page.id);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('review')
|
||||
async review(@Body() dto: PageReviewDto, @AuthUser() user: User) {
|
||||
const page = await this.pageRepo.findById(dto.pageId);
|
||||
if (!page) {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return this.pageService.review(dto.pageId, dto.quality);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('review-list')
|
||||
async reviewList(
|
||||
@Body() dto: { spaceId?: string; onlyDue?: boolean },
|
||||
@Body() pagination: PaginationOptions,
|
||||
@AuthUser() user: User,
|
||||
) {
|
||||
if (dto.spaceId) {
|
||||
const ability = await this.spaceAbility.createForUser(user, dto.spaceId);
|
||||
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
return this.pageService.getPagesToReview(
|
||||
user.id,
|
||||
pagination,
|
||||
dto.spaceId,
|
||||
dto.onlyDue ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ContentOperation, UpdatePageDto } from '../dto/update-page.dto';
|
||||
import { PageRepo } from '@docmost/db/repos/page/page.repo';
|
||||
import { PagePermissionRepo } from '@docmost/db/repos/page/page-permission.repo';
|
||||
import { InsertablePage, Page, User } from '@docmost/db/types/entity.types';
|
||||
import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
|
||||
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
|
||||
import {
|
||||
CursorPaginationResult,
|
||||
@@ -71,7 +72,8 @@ export class PageService {
|
||||
private eventEmitter: EventEmitter2,
|
||||
private collaborationGateway: CollaborationGateway,
|
||||
private readonly watcherService: WatcherService,
|
||||
) {}
|
||||
private readonly spaceMemberRepo: SpaceMemberRepo,
|
||||
) { }
|
||||
|
||||
async findById(
|
||||
pageId: string,
|
||||
@@ -1066,4 +1068,133 @@ export class PageService {
|
||||
|
||||
return pages.filter((p) => includedIds.has(p.id));
|
||||
}
|
||||
|
||||
async review(pageId: string, quality: number): Promise<Page> {
|
||||
console.log('FSRS REVIEW:', { pageId, quality });
|
||||
const page = await this.pageRepo.findById(pageId);
|
||||
if (!page) {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
|
||||
// FSRS v4.5 Weights
|
||||
const w = [
|
||||
0.4025, 1.4612, 3.3458, 15.6922, 5.8483, 1.2081, 1.2946, 0.0014, 1.5478,
|
||||
0.133, 1.0124, 2.4467, 0.0641, 0.5044, 1.242, 0.2836, 2.8536,
|
||||
];
|
||||
|
||||
let { stability: rawStability, difficulty: rawDifficulty, lapses, state, repetitionCount, lastReview } = page;
|
||||
|
||||
// Default values if null
|
||||
const stability = Number(rawStability) || 0;
|
||||
const difficulty = Number(rawDifficulty) || 0;
|
||||
lapses = lapses || 0;
|
||||
state = state || 0; // 0: New, 1: Learning, 2: Review, 3: Relearning
|
||||
repetitionCount = repetitionCount || 0;
|
||||
|
||||
const now = new Date();
|
||||
const elapsedDays = lastReview ? Math.max(0, Math.floor((now.getTime() - new Date(lastReview).getTime()) / (1000 * 60 * 60 * 24))) : 0;
|
||||
|
||||
let nextStability = 0;
|
||||
let nextDifficulty = 0;
|
||||
let nextState = state;
|
||||
|
||||
if (state === 0 || !lastReview) {
|
||||
// First review
|
||||
nextStability = w[quality - 1];
|
||||
nextDifficulty = w[4] - w[5] * (quality - 3);
|
||||
nextState = quality === 1 ? 1 : 2; // If Again, move to Learning, else Review
|
||||
} else {
|
||||
const retrievability = Math.pow(0.9, elapsedDays / stability);
|
||||
|
||||
if (quality === 1) {
|
||||
// Failed
|
||||
lapses++;
|
||||
nextDifficulty = Math.min(Math.max(difficulty + w[6], 1), 10);
|
||||
nextStability = w[10] * Math.pow(nextDifficulty, -w[11]) * (Math.pow(stability + 1, w[12]) - 1) * Math.exp(w[13] * (1 - retrievability));
|
||||
nextState = 3; // Relearning
|
||||
} else {
|
||||
// Success
|
||||
nextDifficulty = Math.min(Math.max(difficulty - w[6] * (quality - 3), 1), 10);
|
||||
const hardPenalty = quality === 2 ? w[14] : 1;
|
||||
const easyBonus = quality === 4 ? w[15] : 1;
|
||||
|
||||
nextStability = stability * (1 + Math.exp(w[7]) * (11 - nextDifficulty) * Math.pow(stability, -w[8]) * (Math.exp(w[9] * (1 - retrievability)) - 1) * hardPenalty * easyBonus);
|
||||
nextState = 2; // Review
|
||||
}
|
||||
}
|
||||
|
||||
// Constraints
|
||||
nextStability = Math.min(Math.max(nextStability, 0.1), 36500);
|
||||
|
||||
// FSRS interval formula: I = S * ln(target_recall) / ln(0.9)
|
||||
// For default target_recall = 0.9, I = S
|
||||
const exactReviewInterval = nextStability; // Keep as float for precision
|
||||
const nextReviewDate = new Date();
|
||||
// Convert days (stability) to minutes for precision
|
||||
nextReviewDate.setMinutes(nextReviewDate.getMinutes() + Math.round(exactReviewInterval * 24 * 60));
|
||||
|
||||
await this.pageRepo.updatePage(
|
||||
{
|
||||
nextReviewDate,
|
||||
lastReview: now,
|
||||
stability: nextStability,
|
||||
difficulty: nextDifficulty,
|
||||
lapses,
|
||||
state: nextState,
|
||||
repetitionCount: repetitionCount + 1,
|
||||
reviewInterval: Math.round(exactReviewInterval), // DB column is int4, must be integer
|
||||
},
|
||||
pageId,
|
||||
);
|
||||
|
||||
return this.pageRepo.findById(pageId);
|
||||
}
|
||||
|
||||
async getPagesToReview(userId: string, pagination: PaginationOptions, spaceId?: string, onlyDue = true) {
|
||||
let query = this.db
|
||||
.selectFrom('pages')
|
||||
.innerJoin('spaces', 'spaces.id', 'pages.spaceId')
|
||||
.select([
|
||||
'pages.id',
|
||||
'pages.slugId',
|
||||
'pages.title',
|
||||
'pages.icon',
|
||||
'pages.spaceId',
|
||||
'pages.nextReviewDate',
|
||||
'pages.easeFactor',
|
||||
'pages.repetitionCount',
|
||||
'pages.reviewInterval',
|
||||
'pages.createdAt',
|
||||
'pages.updatedAt',
|
||||
])
|
||||
.select(
|
||||
sql<{ name: string; slug: string }>`json_build_object('name', spaces.name, 'slug', spaces.slug)`.as('space'),
|
||||
)
|
||||
.where('pages.nextReviewDate', 'is not', null)
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.orderBy('pages.nextReviewDate', 'asc');
|
||||
|
||||
if (onlyDue) {
|
||||
query = query.where('pages.nextReviewDate', '<=', new Date());
|
||||
}
|
||||
|
||||
if (spaceId) {
|
||||
query = query.where('pages.spaceId', '=', spaceId);
|
||||
} else {
|
||||
query = query.where('pages.spaceId', 'in', this.spaceMemberRepo.getUserSpaceIdsQuery(userId));
|
||||
}
|
||||
|
||||
return executeWithCursorPagination(query, {
|
||||
perPage: pagination.limit,
|
||||
cursor: pagination.cursor,
|
||||
fields: [
|
||||
{ expression: 'pages.nextReviewDate', direction: 'asc' },
|
||||
{ expression: 'pages.id', direction: 'asc' },
|
||||
],
|
||||
parseCursor: (cursor: any) => ({
|
||||
nextReviewDate: new Date(cursor.nextReviewDate),
|
||||
id: cursor.id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ export class TrashCleanupService {
|
||||
|
||||
for (const workspace of workspaces) {
|
||||
const retentionDays =
|
||||
workspace.trashRetentionDays ?? DEFAULT_RETENTION_DAYS;
|
||||
workspace.trashRetentionDays != null
|
||||
? Number(workspace.trashRetentionDays)
|
||||
: DEFAULT_RETENTION_DAYS;
|
||||
|
||||
const retentionDate = new Date();
|
||||
retentionDate.setDate(retentionDate.getDate() - retentionDays);
|
||||
|
||||
@@ -366,9 +366,9 @@ export class WorkspaceService {
|
||||
|
||||
if (
|
||||
typeof updateWorkspaceDto.trashRetentionDays !== 'undefined' &&
|
||||
updateWorkspaceDto.trashRetentionDays !== ws.trashRetentionDays
|
||||
updateWorkspaceDto.trashRetentionDays !== Number(ws.trashRetentionDays)
|
||||
) {
|
||||
before.trashRetentionDays = ws.trashRetentionDays;
|
||||
before.trashRetentionDays = ws.trashRetentionDays != null ? Number(ws.trashRetentionDays) : null;
|
||||
after.trashRetentionDays = updateWorkspaceDto.trashRetentionDays;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.alterTable('pages')
|
||||
.addColumn('next_review_date', 'timestamptz')
|
||||
.addColumn('ease_factor', 'float8', (col) => col.defaultTo(2.5).notNull())
|
||||
.addColumn('repetition_count', 'int4', (col) => col.defaultTo(0).notNull())
|
||||
.addColumn('review_interval', 'int4', (col) => col.defaultTo(0).notNull())
|
||||
.execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.alterTable('pages')
|
||||
.dropColumn('next_review_date')
|
||||
.dropColumn('ease_factor')
|
||||
.dropColumn('repetition_count')
|
||||
.dropColumn('review_interval')
|
||||
.execute();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.alterTable('pages')
|
||||
.addColumn('stability', 'decimal', (col) => col.defaultTo(0))
|
||||
.addColumn('difficulty', 'decimal', (col) => col.defaultTo(0))
|
||||
.addColumn('lapses', 'integer', (col) => col.defaultTo(0))
|
||||
.addColumn('state', 'integer', (col) => col.defaultTo(0))
|
||||
.addColumn('last_review', 'timestamptz')
|
||||
.execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.alterTable('pages')
|
||||
.dropColumn('stability')
|
||||
.dropColumn('difficulty')
|
||||
.dropColumn('lapses')
|
||||
.dropColumn('state')
|
||||
.dropColumn('last_review')
|
||||
.execute();
|
||||
}
|
||||
@@ -42,6 +42,15 @@ export class PageRepo {
|
||||
'updatedAt',
|
||||
'deletedAt',
|
||||
'contributorIds',
|
||||
'nextReviewDate',
|
||||
'easeFactor',
|
||||
'repetitionCount',
|
||||
'reviewInterval',
|
||||
'stability',
|
||||
'difficulty',
|
||||
'lapses',
|
||||
'state',
|
||||
'lastReview',
|
||||
];
|
||||
|
||||
async findById(
|
||||
|
||||
+172
-166
@@ -3,18 +3,13 @@
|
||||
* Please do not edit it manually.
|
||||
*/
|
||||
|
||||
import type { ColumnType } from 'kysely';
|
||||
import type { ColumnType } from "kysely";
|
||||
|
||||
export type Generated<T> =
|
||||
T extends ColumnType<infer S, infer I, infer U>
|
||||
? ColumnType<S, I | undefined, U>
|
||||
: ColumnType<T, T | undefined, T>;
|
||||
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
||||
? ColumnType<S, I | undefined, U>
|
||||
: ColumnType<T, T | undefined, T>;
|
||||
|
||||
export type Int8 = ColumnType<
|
||||
string,
|
||||
bigint | number | string,
|
||||
bigint | number | string
|
||||
>;
|
||||
export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>;
|
||||
|
||||
export type Json = JsonValue;
|
||||
|
||||
@@ -28,17 +23,44 @@ export type JsonPrimitive = boolean | number | string | null;
|
||||
|
||||
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
||||
|
||||
export type Numeric = ColumnType<string, number | string, number | string>;
|
||||
|
||||
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
||||
|
||||
export interface AiChatMessages {
|
||||
chatId: string;
|
||||
content: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
deletedAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
metadata: Json | null;
|
||||
role: string;
|
||||
toolCalls: Json | null;
|
||||
tsv: string | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
userId: string | null;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface AiChats {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string;
|
||||
deletedAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
title: string | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface ApiKeys {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string;
|
||||
deletedAt: Timestamp | null;
|
||||
expiresAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
lastUsedAt: Timestamp | null;
|
||||
name: string | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
creatorId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
@@ -93,25 +115,25 @@ export interface AuthProviders {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
deletedAt: Timestamp | null;
|
||||
groupSync: Generated<boolean>;
|
||||
id: Generated<string>;
|
||||
isEnabled: Generated<boolean>;
|
||||
groupSync: Generated<boolean>;
|
||||
ldapBaseDn: string | null;
|
||||
ldapBindDn: string | null;
|
||||
ldapBindPassword: string | null;
|
||||
ldapConfig: Generated<Json | null>;
|
||||
ldapTlsCaCert: string | null;
|
||||
ldapTlsEnabled: Generated<boolean | null>;
|
||||
ldapUrl: string | null;
|
||||
ldapUserAttributes: Json | null;
|
||||
ldapUserAttributes: Generated<Json | null>;
|
||||
ldapUserSearchFilter: string | null;
|
||||
ldapConfig: Json | null;
|
||||
settings: Json | null;
|
||||
name: string;
|
||||
oidcClientId: string | null;
|
||||
oidcClientSecret: string | null;
|
||||
oidcIssuer: string | null;
|
||||
samlCertificate: string | null;
|
||||
samlUrl: string | null;
|
||||
settings: Generated<Json | null>;
|
||||
type: string;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
workspaceId: string;
|
||||
@@ -176,14 +198,14 @@ export interface Comments {
|
||||
}
|
||||
|
||||
export interface Favorites {
|
||||
createdAt: Generated<Timestamp>;
|
||||
id: Generated<string>;
|
||||
userId: string;
|
||||
pageId: string | null;
|
||||
spaceId: string | null;
|
||||
templateId: string | null;
|
||||
type: string;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface FileTasks {
|
||||
@@ -226,6 +248,34 @@ export interface GroupUsers {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface Notifications {
|
||||
actorId: string | null;
|
||||
archivedAt: Timestamp | null;
|
||||
commentId: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
data: Json | null;
|
||||
emailedAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
pageId: string | null;
|
||||
pageVerificationId: string | null;
|
||||
readAt: Timestamp | null;
|
||||
spaceId: string | null;
|
||||
type: string;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface PageAccess {
|
||||
accessLevel: string;
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
id: Generated<string>;
|
||||
pageId: string;
|
||||
spaceId: string;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface PageHistory {
|
||||
content: Json | null;
|
||||
contributorIds: Generated<string[] | null>;
|
||||
@@ -244,6 +294,17 @@ export interface PageHistory {
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface PagePermissions {
|
||||
addedById: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
groupId: string | null;
|
||||
id: Generated<string>;
|
||||
pageAccessId: string;
|
||||
role: string;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
userId: string | null;
|
||||
}
|
||||
|
||||
export interface Pages {
|
||||
content: Json | null;
|
||||
contributorIds: Generated<string[] | null>;
|
||||
@@ -252,14 +313,23 @@ export interface Pages {
|
||||
creatorId: string | null;
|
||||
deletedAt: Timestamp | null;
|
||||
deletedById: string | null;
|
||||
difficulty: Generated<Numeric | null>;
|
||||
easeFactor: Generated<number>;
|
||||
icon: string | null;
|
||||
id: Generated<string>;
|
||||
isLocked: Generated<boolean>;
|
||||
lapses: Generated<number | null>;
|
||||
lastReview: Timestamp | null;
|
||||
lastUpdatedById: string | null;
|
||||
nextReviewDate: Timestamp | null;
|
||||
parentPageId: string | null;
|
||||
position: string | null;
|
||||
repetitionCount: Generated<number>;
|
||||
reviewInterval: Generated<number>;
|
||||
slugId: string;
|
||||
spaceId: string;
|
||||
stability: Generated<Numeric | null>;
|
||||
state: Generated<number | null>;
|
||||
textContent: string | null;
|
||||
title: string | null;
|
||||
tsv: string | null;
|
||||
@@ -268,6 +338,39 @@ export interface Pages {
|
||||
ydoc: Buffer | null;
|
||||
}
|
||||
|
||||
export interface PageVerifications {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
data: Json | null;
|
||||
expiresAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
mode: string | null;
|
||||
pageId: string;
|
||||
periodAmount: number | null;
|
||||
periodUnit: string | null;
|
||||
rejectedAt: Timestamp | null;
|
||||
rejectedById: string | null;
|
||||
rejectionComment: string | null;
|
||||
requestedAt: Timestamp | null;
|
||||
requestedById: string | null;
|
||||
spaceId: string;
|
||||
status: string | null;
|
||||
type: Generated<string>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
verifiedAt: Timestamp | null;
|
||||
verifiedById: string | null;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface PageVerifiers {
|
||||
addedById: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
id: Generated<string>;
|
||||
isPrimary: Generated<boolean>;
|
||||
pageVerificationId: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface Shares {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
@@ -310,6 +413,25 @@ export interface Spaces {
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface Templates {
|
||||
collaboratorIds: string[] | null;
|
||||
content: Json | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
deletedAt: Timestamp | null;
|
||||
description: string | null;
|
||||
icon: string | null;
|
||||
id: Generated<string>;
|
||||
lastUpdatedById: string | null;
|
||||
spaceId: string | null;
|
||||
textContent: string | null;
|
||||
title: string | null;
|
||||
tsv: string | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
workspaceId: string;
|
||||
ydoc: Buffer | null;
|
||||
}
|
||||
|
||||
export interface UserMfa {
|
||||
backupCodes: string[] | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
@@ -329,12 +451,12 @@ export interface Users {
|
||||
deletedAt: Timestamp | null;
|
||||
email: string;
|
||||
emailVerifiedAt: Timestamp | null;
|
||||
hasGeneratedPassword: Generated<boolean>;
|
||||
id: Generated<string>;
|
||||
invitedById: string | null;
|
||||
lastActiveAt: Timestamp | null;
|
||||
lastLoginAt: Timestamp | null;
|
||||
locale: string | null;
|
||||
hasGeneratedPassword: Generated<boolean | null>;
|
||||
name: string | null;
|
||||
password: string | null;
|
||||
role: string | null;
|
||||
@@ -344,6 +466,21 @@ export interface Users {
|
||||
workspaceId: string | null;
|
||||
}
|
||||
|
||||
export interface UserSessions {
|
||||
createdAt: Generated<Timestamp>;
|
||||
deviceName: string | null;
|
||||
expiresAt: Timestamp;
|
||||
geoLocation: string | null;
|
||||
id: Generated<string>;
|
||||
ipAddress: string | null;
|
||||
lastActiveAt: Generated<Timestamp>;
|
||||
metadata: Json | null;
|
||||
revokedAt: Timestamp | null;
|
||||
userAgent: string | null;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface UserTokens {
|
||||
createdAt: Generated<Timestamp>;
|
||||
expiresAt: Timestamp | null;
|
||||
@@ -355,6 +492,18 @@ export interface UserTokens {
|
||||
workspaceId: string | null;
|
||||
}
|
||||
|
||||
export interface Watchers {
|
||||
addedById: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
id: Generated<string>;
|
||||
mutedAt: Timestamp | null;
|
||||
pageId: string | null;
|
||||
spaceId: string;
|
||||
type: string;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceInvitations {
|
||||
createdAt: Generated<Timestamp>;
|
||||
email: string | null;
|
||||
@@ -368,8 +517,7 @@ export interface WorkspaceInvitations {
|
||||
}
|
||||
|
||||
export interface Workspaces {
|
||||
auditRetentionDays: Generated<number>;
|
||||
trashRetentionDays: Generated<number>;
|
||||
auditRetentionDays: Int8 | null;
|
||||
billingEmail: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
customDomain: string | null;
|
||||
@@ -389,156 +537,14 @@ export interface Workspaces {
|
||||
settings: Json | null;
|
||||
status: string | null;
|
||||
stripeCustomerId: string | null;
|
||||
trashRetentionDays: Int8 | null;
|
||||
trialEndAt: Timestamp | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface Notifications {
|
||||
id: Generated<string>;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
type: string;
|
||||
actorId: string | null;
|
||||
pageId: string | null;
|
||||
spaceId: string | null;
|
||||
commentId: string | null;
|
||||
pageVerificationId: string | null;
|
||||
data: Json | null;
|
||||
readAt: Timestamp | null;
|
||||
emailedAt: Timestamp | null;
|
||||
archivedAt: Timestamp | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface Watchers {
|
||||
id: Generated<string>;
|
||||
userId: string;
|
||||
pageId: string | null;
|
||||
spaceId: string;
|
||||
workspaceId: string;
|
||||
type: string;
|
||||
addedById: string | null;
|
||||
mutedAt: Timestamp | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface PageAccess {
|
||||
id: Generated<string>;
|
||||
pageId: string;
|
||||
workspaceId: string;
|
||||
spaceId: string;
|
||||
accessLevel: string;
|
||||
creatorId: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface PagePermissions {
|
||||
id: Generated<string>;
|
||||
pageAccessId: string;
|
||||
userId: string | null;
|
||||
groupId: string | null;
|
||||
role: string;
|
||||
addedById: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface PageVerifications {
|
||||
id: Generated<string>;
|
||||
pageId: string;
|
||||
workspaceId: string;
|
||||
spaceId: string;
|
||||
type: Generated<string>;
|
||||
status: string | null;
|
||||
mode: string | null;
|
||||
periodAmount: number | null;
|
||||
periodUnit: string | null;
|
||||
verifiedAt: Timestamp | null;
|
||||
verifiedById: string | null;
|
||||
expiresAt: Timestamp | null;
|
||||
requestedAt: Timestamp | null;
|
||||
requestedById: string | null;
|
||||
rejectedAt: Timestamp | null;
|
||||
rejectedById: string | null;
|
||||
rejectionComment: string | null;
|
||||
data: Json | null;
|
||||
creatorId: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface PageVerifiers {
|
||||
id: Generated<string>;
|
||||
pageVerificationId: string;
|
||||
userId: string;
|
||||
isPrimary: Generated<boolean>;
|
||||
addedById: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface Templates {
|
||||
id: Generated<string>;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
content: Json | null;
|
||||
ydoc: Buffer | null;
|
||||
icon: string | null;
|
||||
spaceId: string | null;
|
||||
workspaceId: string;
|
||||
creatorId: string | null;
|
||||
lastUpdatedById: string | null;
|
||||
collaboratorIds: string[] | null;
|
||||
textContent: string | null;
|
||||
tsv: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
deletedAt: Timestamp | null;
|
||||
}
|
||||
|
||||
export interface AiChats {
|
||||
id: Generated<string>;
|
||||
workspaceId: string;
|
||||
creatorId: string;
|
||||
title: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
deletedAt: Timestamp | null;
|
||||
}
|
||||
|
||||
export interface AiChatMessages {
|
||||
id: Generated<string>;
|
||||
chatId: string;
|
||||
workspaceId: string;
|
||||
userId: string | null;
|
||||
role: string;
|
||||
content: string | null;
|
||||
toolCalls: Json | null;
|
||||
metadata: Json | null;
|
||||
tsv: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
deletedAt: Timestamp | null;
|
||||
}
|
||||
|
||||
export interface UserSessions {
|
||||
id: Generated<string>;
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
deviceName: string | null;
|
||||
userAgent: string | null;
|
||||
ipAddress: string | null;
|
||||
geoLocation: string | null;
|
||||
metadata: Json | null;
|
||||
lastActiveAt: Generated<Timestamp>;
|
||||
expiresAt: Timestamp;
|
||||
revokedAt: Timestamp | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface DB {
|
||||
aiChats: AiChats;
|
||||
aiChatMessages: AiChatMessages;
|
||||
aiChats: AiChats;
|
||||
apiKeys: ApiKeys;
|
||||
attachments: Attachments;
|
||||
audit: Audit;
|
||||
@@ -553,11 +559,11 @@ export interface DB {
|
||||
groupUsers: GroupUsers;
|
||||
notifications: Notifications;
|
||||
pageAccess: PageAccess;
|
||||
pagePermissions: PagePermissions;
|
||||
pageHistory: PageHistory;
|
||||
pagePermissions: PagePermissions;
|
||||
pages: Pages;
|
||||
pageVerifications: PageVerifications;
|
||||
pageVerifiers: PageVerifiers;
|
||||
pages: Pages;
|
||||
shares: Shares;
|
||||
spaceMembers: SpaceMembers;
|
||||
spaces: Spaces;
|
||||
|
||||
Reference in New Issue
Block a user