Convex: per-user dotfiles + environment storage (encrypted)

- schema: userDotfiles (one encrypted row per file, HOME-relative path) and
  userEnvironment (home username + optional public dotfiles repo + setup command)
- userDotfiles.ts: list/remove/removeDirectory/rename + internal upsert/getRaw
- userDotfilesNode.ts ('use node'): putFile/importFiles/getFileContent (encrypt
  /decrypt via secretCrypto) + getEnvironmentForJob (worker-token, returns the
  owner's decrypted dotfiles + repo/setup config)
- userEnvironment.ts: getMine/updateMine + getRawEnvironmentForJobInternal
- model.ts: deriveHomeUsername + normalizeDotfilePath helpers
This commit is contained in:
Gabriel Brown
2026-06-24 09:38:43 -04:00
parent 32a71f00ca
commit 683fc62129
5 changed files with 402 additions and 0 deletions
+24
View File
@@ -348,6 +348,30 @@ const applicationTables = {
})
.index('by_user', ['userId'])
.index('by_user_provider', ['userId', 'provider']),
// Per-user dotfiles: one row per file, materialized into the workspace
// container's HOME. Content is encrypted at rest (reuses secretCrypto).
// `path` is relative to HOME, e.g. ".bashrc" or ".config/nvim/init.lua".
userDotfiles: defineTable({
ownerId: v.id('users'),
path: v.string(),
encryptedContent: v.string(),
size: v.number(),
isExecutable: v.optional(v.boolean()),
updatedAt: v.number(),
})
.index('by_owner', ['ownerId'])
.index('by_owner_path', ['ownerId', 'path']),
// Per-user environment config: the persistent home username + an optional
// public dotfiles repo and setup command run in the container.
userEnvironment: defineTable({
ownerId: v.id('users'),
enabled: v.boolean(),
homeUsername: v.optional(v.string()),
dotfilesRepoUrl: v.optional(v.string()),
dotfilesRepoRef: v.optional(v.string()),
setupCommand: v.optional(v.string()),
updatedAt: v.number(),
}).index('by_owner', ['ownerId']),
aiProviderProfiles: defineTable({
ownerId: v.id('users'),
name: v.string(),