mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 08:52:21 +00:00
230 lines
6.1 KiB
TypeScript
230 lines
6.1 KiB
TypeScript
import { authTables } from '@convex-dev/auth/server'
|
|
import { defineSchema, defineTable } from 'convex/server'
|
|
import { v } from 'convex/values'
|
|
import { EMBEDDING_DIMENSIONS } from './lib/embeddings'
|
|
|
|
const users = defineTable({
|
|
name: v.optional(v.string()),
|
|
image: v.optional(v.string()),
|
|
email: v.optional(v.string()),
|
|
emailVerificationTime: v.optional(v.number()),
|
|
phone: v.optional(v.string()),
|
|
phoneVerificationTime: v.optional(v.number()),
|
|
isAnonymous: v.optional(v.boolean()),
|
|
handle: v.optional(v.string()),
|
|
displayName: v.optional(v.string()),
|
|
bio: v.optional(v.string()),
|
|
role: v.optional(v.union(v.literal('admin'), v.literal('moderator'), v.literal('user'))),
|
|
deletedAt: v.optional(v.number()),
|
|
createdAt: v.optional(v.number()),
|
|
updatedAt: v.optional(v.number()),
|
|
})
|
|
.index('email', ['email'])
|
|
.index('phone', ['phone'])
|
|
.index('handle', ['handle'])
|
|
|
|
const skills = defineTable({
|
|
slug: v.string(),
|
|
displayName: v.string(),
|
|
summary: v.optional(v.string()),
|
|
ownerUserId: v.id('users'),
|
|
canonicalSkillId: v.optional(v.id('skills')),
|
|
forkOf: v.optional(
|
|
v.object({
|
|
skillId: v.id('skills'),
|
|
kind: v.union(v.literal('fork'), v.literal('duplicate')),
|
|
version: v.optional(v.string()),
|
|
at: v.number(),
|
|
}),
|
|
),
|
|
latestVersionId: v.optional(v.id('skillVersions')),
|
|
tags: v.record(v.string(), v.id('skillVersions')),
|
|
softDeletedAt: v.optional(v.number()),
|
|
badges: v.object({
|
|
redactionApproved: v.optional(
|
|
v.object({
|
|
byUserId: v.id('users'),
|
|
at: v.number(),
|
|
}),
|
|
),
|
|
}),
|
|
batch: v.optional(v.string()),
|
|
stats: v.object({
|
|
downloads: v.number(),
|
|
installsCurrent: v.optional(v.number()),
|
|
installsAllTime: v.optional(v.number()),
|
|
stars: v.number(),
|
|
versions: v.number(),
|
|
comments: v.number(),
|
|
}),
|
|
createdAt: v.number(),
|
|
updatedAt: v.number(),
|
|
})
|
|
.index('by_slug', ['slug'])
|
|
.index('by_owner', ['ownerUserId'])
|
|
.index('by_updated', ['updatedAt'])
|
|
.index('by_batch', ['batch'])
|
|
|
|
const skillVersions = defineTable({
|
|
skillId: v.id('skills'),
|
|
version: v.string(),
|
|
fingerprint: v.optional(v.string()),
|
|
changelog: v.string(),
|
|
changelogSource: v.optional(v.union(v.literal('auto'), v.literal('user'))),
|
|
files: v.array(
|
|
v.object({
|
|
path: v.string(),
|
|
size: v.number(),
|
|
storageId: v.id('_storage'),
|
|
sha256: v.string(),
|
|
contentType: v.optional(v.string()),
|
|
}),
|
|
),
|
|
parsed: v.object({
|
|
frontmatter: v.record(v.string(), v.any()),
|
|
metadata: v.optional(v.any()),
|
|
clawdis: v.optional(v.any()),
|
|
}),
|
|
createdBy: v.id('users'),
|
|
createdAt: v.number(),
|
|
softDeletedAt: v.optional(v.number()),
|
|
})
|
|
.index('by_skill', ['skillId'])
|
|
.index('by_skill_version', ['skillId', 'version'])
|
|
|
|
const skillVersionFingerprints = defineTable({
|
|
skillId: v.id('skills'),
|
|
versionId: v.id('skillVersions'),
|
|
fingerprint: v.string(),
|
|
createdAt: v.number(),
|
|
})
|
|
.index('by_version', ['versionId'])
|
|
.index('by_fingerprint', ['fingerprint'])
|
|
.index('by_skill_fingerprint', ['skillId', 'fingerprint'])
|
|
|
|
const skillEmbeddings = defineTable({
|
|
skillId: v.id('skills'),
|
|
versionId: v.id('skillVersions'),
|
|
ownerId: v.id('users'),
|
|
embedding: v.array(v.number()),
|
|
isLatest: v.boolean(),
|
|
isApproved: v.boolean(),
|
|
visibility: v.string(),
|
|
updatedAt: v.number(),
|
|
})
|
|
.index('by_skill', ['skillId'])
|
|
.index('by_version', ['versionId'])
|
|
.vectorIndex('by_embedding', {
|
|
vectorField: 'embedding',
|
|
dimensions: EMBEDDING_DIMENSIONS,
|
|
filterFields: ['visibility'],
|
|
})
|
|
|
|
const comments = defineTable({
|
|
skillId: v.id('skills'),
|
|
userId: v.id('users'),
|
|
body: v.string(),
|
|
createdAt: v.number(),
|
|
softDeletedAt: v.optional(v.number()),
|
|
deletedBy: v.optional(v.id('users')),
|
|
})
|
|
.index('by_skill', ['skillId'])
|
|
.index('by_user', ['userId'])
|
|
|
|
const stars = defineTable({
|
|
skillId: v.id('skills'),
|
|
userId: v.id('users'),
|
|
createdAt: v.number(),
|
|
})
|
|
.index('by_skill', ['skillId'])
|
|
.index('by_user', ['userId'])
|
|
.index('by_skill_user', ['skillId', 'userId'])
|
|
|
|
const auditLogs = defineTable({
|
|
actorUserId: v.id('users'),
|
|
action: v.string(),
|
|
targetType: v.string(),
|
|
targetId: v.string(),
|
|
metadata: v.optional(v.any()),
|
|
createdAt: v.number(),
|
|
})
|
|
.index('by_actor', ['actorUserId'])
|
|
.index('by_target', ['targetType', 'targetId'])
|
|
|
|
const apiTokens = defineTable({
|
|
userId: v.id('users'),
|
|
label: v.string(),
|
|
prefix: v.string(),
|
|
tokenHash: v.string(),
|
|
createdAt: v.number(),
|
|
lastUsedAt: v.optional(v.number()),
|
|
revokedAt: v.optional(v.number()),
|
|
})
|
|
.index('by_user', ['userId'])
|
|
.index('by_hash', ['tokenHash'])
|
|
|
|
const rateLimits = defineTable({
|
|
key: v.string(),
|
|
windowStart: v.number(),
|
|
count: v.number(),
|
|
limit: v.number(),
|
|
updatedAt: v.number(),
|
|
})
|
|
.index('by_key_window', ['key', 'windowStart'])
|
|
.index('by_key', ['key'])
|
|
|
|
const userSyncRoots = defineTable({
|
|
userId: v.id('users'),
|
|
rootId: v.string(),
|
|
label: v.string(),
|
|
firstSeenAt: v.number(),
|
|
lastSeenAt: v.number(),
|
|
expiredAt: v.optional(v.number()),
|
|
})
|
|
.index('by_user', ['userId'])
|
|
.index('by_user_root', ['userId', 'rootId'])
|
|
|
|
const userSkillInstalls = defineTable({
|
|
userId: v.id('users'),
|
|
skillId: v.id('skills'),
|
|
firstSeenAt: v.number(),
|
|
lastSeenAt: v.number(),
|
|
activeRoots: v.number(),
|
|
lastVersion: v.optional(v.string()),
|
|
})
|
|
.index('by_user', ['userId'])
|
|
.index('by_user_skill', ['userId', 'skillId'])
|
|
.index('by_skill', ['skillId'])
|
|
|
|
const userSkillRootInstalls = defineTable({
|
|
userId: v.id('users'),
|
|
rootId: v.string(),
|
|
skillId: v.id('skills'),
|
|
firstSeenAt: v.number(),
|
|
lastSeenAt: v.number(),
|
|
lastVersion: v.optional(v.string()),
|
|
removedAt: v.optional(v.number()),
|
|
})
|
|
.index('by_user', ['userId'])
|
|
.index('by_user_root', ['userId', 'rootId'])
|
|
.index('by_user_root_skill', ['userId', 'rootId', 'skillId'])
|
|
.index('by_user_skill', ['userId', 'skillId'])
|
|
.index('by_skill', ['skillId'])
|
|
|
|
export default defineSchema({
|
|
...authTables,
|
|
users,
|
|
skills,
|
|
skillVersions,
|
|
skillVersionFingerprints,
|
|
skillEmbeddings,
|
|
comments,
|
|
stars,
|
|
auditLogs,
|
|
apiTokens,
|
|
rateLimits,
|
|
userSyncRoots,
|
|
userSkillInstalls,
|
|
userSkillRootInstalls,
|
|
})
|