fix(core): token writes keep their actor in history but are user-owned in field_sources
fieldOwner(actor) maps every non-plugin actor to "user" wherever field_sources is written (entries, engagements, list ownership from history), so syncs never overwrite a field an API token edited. authenticateAppToken also returns the token name; revokeAppToken reports whether it revoked; listSuggestions queries the canonical work id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e3a759d768
commit
aa8e4db070
@@ -170,11 +170,17 @@ export async function createAppToken(
|
||||
}
|
||||
|
||||
export async function verifyAppToken(db: Db, token: string, scope: TokenScope): Promise<User | null> {
|
||||
return (await authenticateAppToken(db, token, scope))?.user ?? null;
|
||||
}
|
||||
|
||||
/** Like `verifyAppToken`, also returning the token's name (API writes record actor `token:<name>`). */
|
||||
export async function authenticateAppToken(db: Db, token: string, scope: TokenScope): Promise<{ user: User; tokenName: string } | null> {
|
||||
const row = await db.k
|
||||
.selectFrom("app_tokens")
|
||||
.innerJoin("users", "users.id", "app_tokens.user_id")
|
||||
.select([
|
||||
"app_tokens.id as token_id",
|
||||
"app_tokens.name as token_name",
|
||||
"app_tokens.scopes",
|
||||
"users.id",
|
||||
"users.username",
|
||||
@@ -186,17 +192,19 @@ export async function verifyAppToken(db: Db, token: string, scope: TokenScope):
|
||||
.executeTakeFirst();
|
||||
if (!row || !fromJson<string[]>(row.scopes, []).includes(scope)) return null;
|
||||
await db.k.updateTable("app_tokens").set({ last_used_at: nowIso() }).where("id", "=", row.token_id).execute();
|
||||
return toUser(row);
|
||||
return { user: toUser(row), tokenName: row.token_name };
|
||||
}
|
||||
|
||||
export async function revokeAppToken(db: Db, userId: string, id: string): Promise<void> {
|
||||
await db.k
|
||||
/** Revoke one of the user's live tokens. Returns false when no such live token exists (unknown, foreign or revoked). */
|
||||
export async function revokeAppToken(db: Db, userId: string, id: string): Promise<boolean> {
|
||||
const r = await db.k
|
||||
.updateTable("app_tokens")
|
||||
.set({ revoked_at: nowIso() })
|
||||
.where("id", "=", id)
|
||||
.where("user_id", "=", userId)
|
||||
.where("revoked_at", "is", null)
|
||||
.execute();
|
||||
.executeTakeFirst();
|
||||
return Number(r.numUpdatedRows) === 1;
|
||||
}
|
||||
|
||||
export interface AppTokenInfo {
|
||||
|
||||
Reference in New Issue
Block a user