* Edit a hosted property with revision tracking. * Rejects edits to authoritative (has matching discovered_properties) or pending records.
(
domain: string,
input: {
adagents_json?: Record<string, unknown>;
edit_summary: string;
editor_user_id: string;
editor_email?: string;
editor_name?: string;
}
)
| 596 | * Rejects edits to authoritative (has matching discovered_properties) or pending records. |
| 597 | */ |
| 598 | async editCommunityProperty( |
| 599 | domain: string, |
| 600 | input: { |
| 601 | adagents_json?: Record<string, unknown>; |
| 602 | edit_summary: string; |
| 603 | editor_user_id: string; |
| 604 | editor_email?: string; |
| 605 | editor_name?: string; |
| 606 | } |
| 607 | ): Promise<{ property: HostedProperty; revision_number: number }> { |
| 608 | const client = await getClient(); |
| 609 | try { |
| 610 | await client.query('BEGIN'); |
| 611 | |
| 612 | // Lock the row |
| 613 | const lockResult = await client.query<HostedProperty>( |
| 614 | 'SELECT * FROM hosted_properties WHERE publisher_domain = $1 FOR UPDATE', |
| 615 | [domain.toLowerCase()] |
| 616 | ); |
| 617 | if (lockResult.rows.length === 0) { |
| 618 | throw new Error(`Property not found: ${domain}`); |
| 619 | } |
| 620 | |
| 621 | const current = lockResult.rows[0]; |
| 622 | |
| 623 | // Check for authoritative lock (discovered adagents.json exists) |
| 624 | const authCheck = await client.query( |
| 625 | 'SELECT 1 FROM discovered_properties WHERE publisher_domain = $1 LIMIT 1', |
| 626 | [domain.toLowerCase()] |
| 627 | ); |
| 628 | if (authCheck.rows.length > 0) { |
| 629 | throw new Error('Cannot edit authoritative property (managed via adagents.json)'); |
| 630 | } |
| 631 | |
| 632 | if (current.review_status === 'pending') { |
| 633 | throw new Error('Cannot edit property pending review'); |
| 634 | } |
| 635 | |
| 636 | // Get next revision number |
| 637 | const revResult = await client.query<{ next_rev: number }>( |
| 638 | 'SELECT COALESCE(MAX(revision_number), 0) + 1 as next_rev FROM property_revisions WHERE publisher_domain = $1', |
| 639 | [domain.toLowerCase()] |
| 640 | ); |
| 641 | const revisionNumber = revResult.rows[0].next_rev; |
| 642 | |
| 643 | // Snapshot current state as revision |
| 644 | await client.query( |
| 645 | `INSERT INTO property_revisions ( |
| 646 | publisher_domain, revision_number, snapshot, |
| 647 | editor_user_id, editor_email, editor_name, edit_summary |
| 648 | ) VALUES ($1, $2, $3, $4, $5, $6, $7)`, |
| 649 | [ |
| 650 | domain.toLowerCase(), |
| 651 | revisionNumber, |
| 652 | JSON.stringify(current), |
| 653 | input.editor_user_id, |
| 654 | input.editor_email || null, |
| 655 | input.editor_name || null, |
no test coverage detected