@aglyn/plugins-marketplace 1.0.0-beta.151 → 1.0.0-beta.152
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/lib/components/plugin-review-detail.component.js +1 -1
- package/src/lib/components/plugin-review-detail.component.js.map +1 -1
- package/src/lib/server/admin-reviews.js +3 -3
- package/src/lib/server/admin-reviews.js.map +1 -1
- package/src/lib/server/admin-trust.d.ts +51 -0
- package/src/lib/server/admin-trust.js +190 -0
- package/src/lib/server/admin-trust.js.map +1 -0
- package/src/lib/server.js +7 -0
- package/src/lib/server.js.map +1 -1
|
@@ -46,7 +46,7 @@ import { dropCachesForListing } from "./revoke-cache-drop.js";
|
|
|
46
46
|
* verify → verified (✅ badge) reject → rejected (+ reason,
|
|
47
47
|
* notification to the publisher)
|
|
48
48
|
*
|
|
49
|
-
* Realm trust stays a SEPARATE, super-staff grant (
|
|
49
|
+
* Realm trust stays a SEPARATE, super-staff grant (`admin-trust.ts`) —
|
|
50
50
|
* listing/verifying here never signs anything. Every action lands in
|
|
51
51
|
* adminAudit.
|
|
52
52
|
*/ /** Every id the checklist route will accept (AGL-963). */ const REQUIRED_OR_OPTIONAL = new Set(PLUGIN_REVIEW_CHECKLIST.map((item)=>item.id));
|
|
@@ -859,7 +859,7 @@ async function handler(request) {
|
|
|
859
859
|
reviewRejectionCategory: category,
|
|
860
860
|
// REALM TRUST IS WITHDRAWN WITH THE APPROVAL (AGL-2306).
|
|
861
861
|
//
|
|
862
|
-
// `
|
|
862
|
+
// `admin-trust` refuses to grant `trust: 'realm'` unless the
|
|
863
863
|
// version is approved — approval gates the grant. Nothing
|
|
864
864
|
// ungated it: the realm load path checks `hiddenAt`, the sha,
|
|
865
865
|
// the signature and the revocation, and never re-reads
|
|
@@ -869,7 +869,7 @@ async function handler(request) {
|
|
|
869
869
|
// user data, until staff separately reached for the kill
|
|
870
870
|
// switch.
|
|
871
871
|
//
|
|
872
|
-
// The same four fields `
|
|
872
|
+
// The same four fields `admin-trust`'s own revoke branch
|
|
873
873
|
// clears, so there is one shape of "untrusted" rather than
|
|
874
874
|
// two. This does NOT stop the bundle running as a sandboxed
|
|
875
875
|
// plugin — that is what the per-version revocation beside
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/server/admin-reviews.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n REVOKED_VERSION_REVIEW_STATE,\n revocationWithdrawsReviewedClaim,\n shouldStripVerifiedOnTakedown,\n VERIFIED_STRIPPED_STATUS,\n} from '../model/plugin-review-status'\nimport {\n checkPluginBundle,\n isPluginRevoked,\n newestInstallableVersion,\n isStoredVerdictCurrent,\n nextRevocationState,\n PLUGIN_HOST_ABI_VERSION,\n PLUGIN_VERIFIER_VERSION,\n pluginArtifactPath,\n pluginRequestFromWeb,\n readPluginContributions,\n type PluginRevocation,\n type StoredBundleVerdict,\n} from '@aglyn/aglyn/server'\nimport {\n emailUnverifiedResponse,\n findUserByUidAcrossPools,\n firebaseAdmin,\n isImpersonationSession,\n updateExisting,\n} from '@aglyn/tenant-data-admin'\nimport { invalidIdTokenResponse } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport {\n buildRoute,\n compareArtifactVersions,\n Route,\n} from '@aglyn/aglyn/server'\nimport {\n outstandingChecklistItems,\n PLUGIN_REVIEW_CHECKLIST,\n} from '../model/plugin-review-checklist'\nimport {\n pluginRejectionCategory,\n rejectionHeadline,\n rejectionInputError,\n} from '../model/plugin-rejection-categories'\nimport { attestationsForBytes } from '@aglyn/aglyn/app-utils/publisher-attestation'\nimport { VERIFICATION_DECLINE_COOLDOWN_DAYS } from '@aglyn/aglyn/app-utils/marketplace-verification'\nimport {\n PUBLISHER_AGREEMENT_VERSION,\n publisherAgreementState,\n} from '@aglyn/aglyn/app-utils/publisher-agreement'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport { notifyOrgAdmins } from '@aglyn/tenant-data-admin'\n/*\n * The publisher fan-out lives beside the usage-alert one in `_lib` rather\n * than here. Both are multi-recipient platform sends that have to read the\n * platform suppression list before addressing anybody, and that list has to\n * be reachable by a spec that does not drag the admin SDK in behind a route.\n */\nimport { emailPublisher } from './publisher-review-email'\nimport { dropCachesForListing } from './revoke-cache-drop'\n\n/**\n * Marketplace review queue (AGL-432) — Strapi Market's two-phase review\n * as staff tooling. GET returns plugin listings awaiting review\n * (submitted/in_review) with the static-verifier verdict re-run against\n * the stored artifact (the same AGL-426 checks the publish API enforced —\n * re-run here so a reviewer sees them without trusting the publish-time\n * result). POST moves a listing through the lifecycle:\n *\n * start-review → in_review list → listed (publicly browsable)\n * verify → verified (✅ badge) reject → rejected (+ reason,\n * notification to the publisher)\n *\n * Realm trust stays a SEPARATE, super-staff grant (sign-plugin route) —\n * listing/verifying here never signs anything. Every action lands in\n * adminAudit.\n */\n/** Every id the checklist route will accept (AGL-963). */\nconst REQUIRED_OR_OPTIONAL = new Set(\n PLUGIN_REVIEW_CHECKLIST.map((item) => item.id),\n)\n\nconst ACTIONS: Record<string, string> = {\n 'start-review': 'in_review',\n list: 'listed',\n verify: 'verified',\n reject: 'rejected',\n // Moves BACK down the ladder (AGL-965). Review used to be a one-way\n // ratchet: the only retreats were `reject`, which reads as a verdict on\n // the whole listing and notifies the publisher as such, and takedown,\n // which is the kill switch and stops the plugin in every workspace that\n // already installed it. Neither expresses \"pull it from the marketplace\n // while we look again, without breaking the sites already using it\".\n delist: 'in_review',\n unverify: 'listed',\n}\n\n/**\n * One listing in full, for the detail page (AGL-959). The index deals in\n * rows; everything a reviewer needs to actually decide — manifest,\n * capabilities, ABI, verifier findings, per-version trust, takedown state —\n * is assembled here rather than smeared across the list payload.\n */\nasync function listingDetail(\n firestore: FirebaseFirestore.Firestore,\n listingId: string,\n requestedVersion?: string,\n): Promise<Response> {\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const snapshot = await listingRef.get()\n const listing = snapshot.data()\n if (!listing) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n\n const versionsSnapshot = await listingRef\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(25)\n .get()\n const versions = versionsSnapshot.docs.map((doc) => {\n const publishedAt = doc.get('publishedAt')\n return {\n version: String(doc.get('version') ?? doc.id),\n trust: doc.get('trust') ?? null,\n sha256: String(doc.get('sha256') ?? ''),\n hostAbi: Number(doc.get('manifest.hostAbi')) || null,\n capabilities: doc.get('manifest.capabilities') ?? {},\n // What these bytes declare they contribute (AGL-3116); `null` when the\n // version predates the contract and loads under its default.\n contributes: readPluginContributions(doc.get('manifest.contributes')) ?? null,\n // Declared canvas elements (AGL-1031), for THESE bytes. Publisher copy\n // that renders in the customer's element picker and nowhere on the\n // listing page — so without it here, the `element-metadata` criterion\n // asks a reviewer to check text this page never shows (AGL-2486).\n elements: doc.get('manifest.elements') ?? [],\n publishedAt: publishedAt?.toDate?.()?.toISOString() ?? null,\n // Per-version installs (AGL-1036). \"How many workspaces would a revoke\n // actually hit\" is a per-version question, and the listing total shown\n // elsewhere on this page answers a different one.\n installCount: Number(doc.get('installCount') ?? 0),\n activeInstalls: Number(doc.get('activeInstalls') ?? 0),\n signed: Boolean(doc.get('signature')),\n // The repo as declared for THESE bytes (AGL-1076); absent on versions\n // published before it was collected.\n repositoryUrl: String(doc.get('repositoryUrl') ?? ''),\n reviewState: String(doc.get('reviewState') ?? 'pending'),\n grandfathered: Boolean(doc.get('grandfathered')),\n // Server-side only — used to decide whether the verdict below needs\n // recomputing; stripped before the payload goes out.\n verification: doc.get('verification') ?? null,\n reviewChecklist: doc.get('reviewChecklist') ?? null,\n publisherAttestation: doc.get('publisherAttestation') ?? null,\n }\n })\n\n // Publisher is an ORG since AGL-652 — show the name, not the raw id.\n const publisherId = String(listing.profileId ?? '')\n const publisher = publisherId\n ? await firestore.collection('orgs').doc(publisherId).get()\n : null\n\n // Which terms this publisher is actually under (AGL-1077). A reviewer\n // weighing a takedown, a delist, or a revocation is deciding what we are\n // entitled to do — and that is answered by the agreement the ORG accepted,\n // not by the per-version attestation beside it.\n const publisherProfile = publisherId\n ? await firestore.collection('publisherProfiles').doc(publisherId).get()\n : null\n const acceptance = publisherProfile?.get('publisherAgreement') as\n | { version?: string; acceptedBy?: string; acceptedAt?: { toDate?: () => Date } }\n | undefined\n\n // Kill switch, so the page can say whether the plugin is actually stopped\n // rather than only de-listed (AGL-948).\n const revocation = (\n await firestore.collection('revocations').doc(listingId).get()\n ).data()\n\n // The verifier verdict for the version under review (AGL-426), served\n // from the version doc when it is current (AGL-962).\n //\n // `checkPluginBundle` is pure and the artifact is immutable and\n // content-addressed, so a verdict pinned to {sha256, verifierVersion} is\n // exactly as trustworthy as re-running it — and re-running meant\n // downloading up to a megabyte from Storage on EVERY page view. A stored\n // verdict from an older checker, or for different bytes, is ignored.\n // Which version this page is reviewing (AGL-966). Defaults to the oldest\n // version still awaiting a verdict — that is the work — falling back to\n // the latest when everything is decided. A reviewer can pin any version\n // explicitly; the checklist and verifier verdict follow the selection,\n // because both are statements about specific bytes.\n const pendingFirst = [...versions]\n .reverse()\n .find((entry) => entry.reviewState !== 'approved')\n const reviewVersion =\n (requestedVersion &&\n versions.find((entry) => entry.version === requestedVersion)?.version) ||\n pendingFirst?.version ||\n String(listing.latestVersion ?? '')\n const artifactsBucket = process.env.PLUGIN_ARTIFACTS_BUCKET\n const reviewEntry = versions.find((entry) => entry.version === reviewVersion)\n const reviewSha = reviewEntry?.sha256\n const stored = reviewEntry?.verification as StoredBundleVerdict | undefined\n const storedIsCurrent = isStoredVerdictCurrent(stored, reviewSha ?? '')\n\n let verifier: unknown = storedIsCurrent\n ? {\n ok: stored?.ok,\n problems: stored?.problems ?? [],\n // The per-check summary rides along in the stored verdict (AGL-1087)\n // so the page can show what was checked without re-downloading a\n // megabyte of artifact on every view.\n checks: stored?.checks ?? [],\n }\n : null\n let verifierCached = storedIsCurrent\n if (!storedIsCurrent && artifactsBucket && reviewSha) {\n try {\n const [bytes] = await firebaseAdmin\n .app()\n .storage()\n .bucket(artifactsBucket)\n .file(pluginArtifactPath(listingId, reviewVersion, reviewSha))\n .download()\n // The manifest for THESE bytes, so an undeclared network call is a\n // finding rather than a warning (AGL-964). Read from the version doc,\n // never from the listing — capabilities change between versions.\n const result = checkPluginBundle(bytes.toString('utf8'), {\n declaredNetwork: Array.isArray(reviewEntry?.capabilities?.network)\n ? reviewEntry.capabilities.network.map((origin: unknown) =>\n String(origin),\n )\n : [],\n // Compared, never required: a version published before the contract\n // loads under its default, and review must not refuse it for a rule\n // it was never held to.\n declaredContributions: reviewEntry?.contributes ?? null,\n })\n verifier = result\n // Write it back so this sha is verified at most once platform-wide —\n // covers every listing published before the verdict was persisted at\n // publish time, and any version whose checker has since moved on.\n // Best effort: a failed write costs the next reader a re-run, nothing\n // more, so it must never fail the page.\n await listingRef\n .collection('pluginVersions')\n .doc(reviewVersion)\n .set(\n {\n verification: {\n ok: result.ok,\n problems: result.problems,\n checks: result.checks,\n sha256: reviewSha,\n verifierVersion: PLUGIN_VERIFIER_VERSION,\n checkedAt: FieldValue.serverTimestamp(),\n },\n },\n { merge: true },\n )\n .catch(() => undefined)\n } catch {\n verifier = { error: 'artifact unavailable' }\n verifierCached = false\n }\n }\n\n // Who attested, by name (AGL-969). \"A named publisher said this on a date\"\n // is the half that makes a false attestation actionable, and a raw uid\n // names nobody. Best effort — a deleted account must not blank the page.\n const attestationEntries = Object.values(\n (reviewEntry?.publisherAttestation ?? {}) as Record<\n string,\n { by?: string; at?: { toDate?: () => Date }; sha256?: string }\n >,\n ).filter((entry) => entry?.sha256 === reviewSha)\n const attesterUid = attestationEntries.find((entry) => entry.by)?.by\n const attestedAt =\n attestationEntries.find((entry) => entry.at)?.at?.toDate?.()?.toISOString() ??\n null\n let attestedBy: string | null = attesterUid ?? null\n if (attesterUid) {\n try {\n // Across pools (AGL-1122): an SSO attester is invisible to project-level\n // `getUser`, so this fell through to the catch and the review page named\n // the attester by raw uid — indistinguishable from \"account deleted\".\n const found = await findUserByUidAcrossPools(attesterUid)\n if (found) {\n attestedBy =\n found.record.email ?? found.record.displayName ?? attesterUid\n }\n } catch {\n // Account gone — the uid still identifies the statement.\n }\n }\n\n return Response.json(\n {\n listingId,\n displayName: listing.displayName ?? listingId,\n description: listing.description ?? '',\n // The publisher's ask, so the page can offer Decline beside Verify\n // (AGL-1217). Serialized: `decidedAt`/`requestedAt` are Timestamps and\n // this payload crosses JSON.\n verificationRequest: listing.verificationRequest\n ? {\n state: String(listing.verificationRequest.state ?? ''),\n requestedAt:\n listing.verificationRequest.requestedAt?.toDate?.()?.toISOString() ??\n null,\n declineReason: listing.verificationRequest.declineReason ?? null,\n }\n : null,\n readme: listing.readme ?? '',\n license: listing.license ?? '',\n categories: listing.categories ?? [],\n homepageUrl: listing.homepageUrl ?? '',\n // Prefer what the version under review declared (AGL-1076). The\n // listing carries whatever the most recent publish said, and a repo\n // can move between versions — the link a reviewer opens should be the\n // one attested against the bytes in front of them. Falls back to the\n // listing for versions published before this was collected.\n repositoryUrl: reviewEntry?.repositoryUrl || listing.repositoryUrl || '',\n publisherId,\n publisherName: publisher?.get('name') ?? publisherId,\n publisherSlug: publisher?.get('slug') ?? null,\n reviewStatus: listing.reviewStatus ?? 'submitted',\n rejectionReason: listing.rejectionReason ?? '',\n rejectionCategory: listing.rejectionCategory ?? '',\n priceUsd: Number(listing.priceUsd ?? 0),\n latestVersion: String(listing.latestVersion ?? ''),\n // The version the checklist, verifier verdict and approve/reject\n // actions on this payload refer to.\n reviewVersion,\n activeInstalls: Number(listing.activeInstalls ?? 0),\n hidden: Boolean(listing.hiddenAt),\n hiddenReason: String(listing.hiddenReason ?? ''),\n revoked: Boolean(revocation),\n revokedVersions: revocation?.versions ?? null,\n unpublished: Boolean(listing.deletedAt),\n private: listing.visibility === 'private',\n platformHostAbi: PLUGIN_HOST_ABI_VERSION,\n // Where the bundle bytes actually live (AGL-990). Staff-only payload,\n // and a bucket NAME is not a credential — reaching the object still\n // needs a Google account with access. Without it the page cannot build\n // a Cloud console link, and this bucket does not appear in the Firebase\n // console at all, so a reviewer has no way to find it by hand.\n artifactsBucket: artifactsBucket ?? null,\n versions: versions.map(\n // The rest-strip is the point: `verification`, `reviewChecklist` and\n // `publisherAttestation` are named only so they DO NOT reach the\n // client payload, which is what the disable below is for. The\n // duplicate directive that used to sit above `versions.map(` covered\n // a line with nothing unused on it, and this config treats an\n // unused disable as a failure.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ({ verification, reviewChecklist, publisherAttestation, ...entry }) => ({\n ...entry,\n // Per-version kill-switch state (AGL-1085), read through the same\n // helper the loaders use so the page cannot disagree with the\n // runtime about whether these bytes are stopped.\n revoked: isPluginRevoked(\n revocation as PluginRevocation | undefined,\n entry.version,\n ),\n }),\n ),\n // Review checklist for the version under review (AGL-963). Ticks made\n // against different bytes do not count, so a republish starts clean.\n checklist: Object.fromEntries(\n Object.entries(\n (reviewEntry?.reviewChecklist ?? {}) as Record<\n string,\n { by?: string; sha256?: string }\n >,\n )\n .filter(([, entry]) => entry?.sha256 === reviewSha)\n .map(([id, entry]) => [id, { by: entry.by ?? null }]),\n ),\n checklistOutstanding: outstandingChecklistItems(\n reviewEntry?.reviewChecklist as never,\n reviewSha ?? '',\n ),\n // What the publisher stated about THESE bytes (AGL-969). Not a review\n // input — a reviewer still checks everything themselves — but it says\n // what was claimed, so a discrepancy is a documented false statement\n // rather than a difference of opinion. Attestations recorded against\n // other bytes are dropped, exactly like staff ticks.\n attestation: attestationsForBytes(\n reviewEntry?.publisherAttestation as never,\n reviewSha ?? '',\n ),\n attestedBy,\n attestedAt,\n // The publisher agreement this ORG is under (AGL-1077). `current` is\n // computed here rather than shipped as a boolean so the page can say\n // \"on an older version\" — which is a different thing from never\n // having accepted, and matters differently to a takedown decision.\n publisherAgreement: {\n version: acceptance?.version ?? null,\n acceptedAt: acceptance?.acceptedAt?.toDate?.()?.toISOString() ?? null,\n required: PUBLISHER_AGREEMENT_VERSION,\n state: publisherAgreementState(acceptance),\n },\n verifier,\n verifierCached,\n verifierVersion: PLUGIN_VERIFIER_VERSION,\n },\n { status: 200 },\n )\n}\n\n/**\n * Re-derive `latestApprovedVersion` from the versions themselves (AGL-2306).\n *\n * The mirror was written on approval only, with a comment saying it \"only ever\n * moves forward\" — true of approvals, and the reason it is there. What nothing\n * did was move it BACK. A version approved and later rejected on re-review, or\n * killed with the per-version switch, left the listing still advertising it:\n * `host-plugins-card` and `marketplace-update-state` read this field to offer\n * \"Update to vX\", and `install-plugin` would then refuse those exact bytes.\n *\n * Contained, because `install-plugin` recomputes approval live and never\n * trusts this field — no unreviewed or revoked bytes could ship — but it is\n * the AGL-1016 guarantee leaking back out through a badge, which is where\n * AGL-966 came in.\n *\n * Recomputed rather than decremented: \"the newest version that is approved AND\n * not revoked\" is a property of the whole set, and stepping it back one at a\n * time is how a mirror drifts in the other direction.\n *\n * Revoked versions are excluded because the offer has to be installable, and\n * `install-plugin` 409s on a revoked pin. That also makes un-revoking restore\n * the offer, which is why this runs on both revoke and unrevoke.\n *\n * Deletes the field when nothing qualifies: an absent mirror reads as \"no\n * update to offer\", while a stale string reads as an update that does not\n * exist.\n */\nasync function repairLatestApprovedVersion(\n listingRef: FirebaseFirestore.DocumentReference,\n revocation: PluginRevocation | null | undefined,\n): Promise<void> {\n const versions = await listingRef\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(50)\n .get()\n // The DECISION lives in core (`newestInstallableVersion`), where it is\n // testable without a Firestore double and shared with anything else that\n // has to answer \"what is on offer\". This function is only the query.\n const newest = newestInstallableVersion(\n versions.docs.map((doc) => ({\n version: doc.id,\n reviewState: doc.get('reviewState'),\n })),\n revocation,\n compareArtifactVersions,\n )\n await updateExisting(listingRef, {\n latestApprovedVersion: newest ?? FieldValue.delete(),\n updatedAt: FieldValue.serverTimestamp(),\n })\n}\n\nasync function handler(request: Request): Promise<Response> {\n const { method, body, query, headers: rawHeaders } =\n await pluginRequestFromWeb(request)\n const headers = rawHeaders as Partial<Record<string, string>>\n const authorization = headers.authorization ?? ''\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return Response.json({ error: 'Unauthenticated' }, { status: 401 })\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n if (!decoded.email_verified && !isImpersonationSession(decoded)) {\n return emailUnverifiedResponse()\n }\n if (!decoded['staff']) {\n return Response.json({ error: 'Staff only' }, { status: 403 })\n }\n const firestore = firebaseAdmin.app().firestore()\n\n if (method === 'GET') {\n const detailId = String(query['listingId'] ?? '')\n if (detailId) {\n return listingDetail(firestore, detailId, String(query['version'] ?? ''))\n }\n\n // Every plugin listing, bucketed by whether its newest bytes are\n // waiting on a reviewer (AGL-966). The queue used to ask only for\n // `reviewStatus in ['submitted','in_review']`, which meant an UPDATE\n // to an already-listed plugin appeared nowhere: the listing kept its\n // status, so nobody was ever shown the new version. Reading each\n // listing's latest version doc costs one read per listing and needs\n // no new composite index.\n const snapshot = await firestore\n .collection('marketplaceListings')\n .where('type', '==', 'plugin')\n .limit(100)\n .get()\n // Rows only (AGL-961). This used to DOWNLOAD every queued bundle to\n // re-run the verifier, so the index paid a Storage round trip per\n // submission before it could paint. The verifier now runs on the\n // detail page, for the one listing being read.\n const rows = await Promise.all(\n snapshot.docs\n .filter((doc) => !doc.get('deletedAt'))\n .map(async (doc) => {\n const listing = doc.data()\n const version = String(listing.latestVersion ?? '')\n const latest = version\n ? await doc.ref.collection('pluginVersions').doc(version).get()\n : null\n return {\n listingId: doc.id,\n displayName: listing.displayName ?? doc.id,\n description: listing.description ?? '',\n license: listing.license ?? '',\n categories: listing.categories ?? [],\n profileId: listing.profileId,\n reviewStatus: listing.reviewStatus ?? 'submitted',\n priceUsd: Number(listing.priceUsd ?? 0),\n version,\n hidden: Boolean(listing.hiddenAt),\n private: listing.visibility === 'private',\n latestReviewState: String(latest?.get('reviewState') ?? 'pending'),\n grandfathered: Boolean(latest?.get('grandfathered')),\n // The publisher's standing ask for the badge (AGL-1217).\n verificationRequest: listing.verificationRequest ?? null,\n }\n }),\n )\n // Awaiting review = the newest bytes have no approval, whatever the\n // listing says. That is what puts an update in front of staff.\n const queue = rows.filter((row) => row.latestReviewState !== 'approved')\n // A THIRD bucket, deliberately not folded into `queue` (AGL-1217).\n // `queue` means \"these bytes have not been read\"; a verification request\n // means \"this publisher asked us to vouch for who they are\". They are\n // different questions with different work attached, and a listing can\n // sit in both at once — an update pending review from a publisher who\n // has also asked for the badge. Merging them would hide one behind the\n // other and make the count meaningless.\n const verificationRequests = rows.filter(\n (row) => row.verificationRequest?.state === 'pending',\n )\n // Listed/verified plugins with per-version trust (AGL-885): once a\n // listing leaves the queue the Grant/Revoke realm-trust actions used\n // to leave with it — revoking a live plugin's trust required a\n // hand-crafted API call. This block keeps every listed plugin's\n // version trust state administrable.\n const listedSnapshot = {\n docs: snapshot.docs.filter((doc) =>\n ['listed', 'verified'].includes(String(doc.get('reviewStatus') ?? '')),\n ),\n }\n const listed = await Promise.all(\n listedSnapshot.docs.map(async (doc) => {\n const listing = doc.data()\n const versionsSnapshot = await doc.ref\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(10)\n .get()\n const versions = versionsSnapshot.docs.map((versionDoc) => ({\n version: String(versionDoc.get('version') ?? versionDoc.id),\n trust: versionDoc.get('trust') ?? null,\n reviewState: String(versionDoc.get('reviewState') ?? 'pending'),\n }))\n return {\n listingId: doc.id,\n displayName: listing.displayName ?? doc.id,\n reviewStatus: listing.reviewStatus,\n profileId: listing.profileId,\n latestVersion: String(listing.latestVersion ?? ''),\n // Takedown state (AGL-952), so a row shows the current verdict\n // rather than sending a reviewer into the detail page to find\n // out whether the plugin is stopped.\n hidden: Boolean(listing.hiddenAt),\n hiddenReason: String(listing.hiddenReason ?? ''),\n private: listing.visibility === 'private',\n pendingVersions: versions.filter(\n (entry) => entry.reviewState !== 'approved',\n ).length,\n // Summarised for the row; the per-version controls live on the\n // detail page (AGL-960).\n realmVersions: versions.filter((entry) => entry.trust === 'realm')\n .length,\n versionCount: versions.length,\n versions,\n }\n }),\n )\n\n // Publisher names for scanning (AGL-961) — a listing id tells a\n // reviewer nothing. One batched read for both sections.\n const publisherIds = [\n ...new Set(\n [...queue, ...listed]\n .map((entry) => String(entry.profileId ?? ''))\n .filter(Boolean),\n ),\n ]\n const publishers: Record<string, string> = {}\n if (publisherIds.length) {\n const docs = await firestore.getAll(\n ...publisherIds.map((id) => firestore.collection('orgs').doc(id)),\n )\n for (const doc of docs) {\n if (doc.exists) publishers[doc.id] = String(doc.get('name') ?? doc.id)\n }\n }\n return Response.json(\n { queue, listed, publishers, verificationRequests },\n { status: 200 },\n )\n }\n\n if (method !== 'POST') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n const listingId = String(body?.listingId ?? '')\n const action = String(body?.action ?? '')\n\n // Takedown (AGL-658) is separate from the review verdict: it applies to\n // EVERY artifact type, not just plugins, and it must not overwrite a\n // plugin's `reviewStatus` — a hidden plugin that later gets un-hidden\n // should return to the verdict it had, not to square one.\n if (action === 'hide' || action === 'unhide') {\n if (!listingId) {\n return Response.json({ error: 'Missing listingId' }, { status: 400 })\n }\n const hideReason = String(body?.reason ?? '').slice(0, 500)\n if (action === 'hide' && !hideReason.trim()) {\n return Response.json({ error: 'Hiding needs a reason' }, { status: 400 })\n }\n const reviewUid = String(body?.reviewUid ?? '')\n const target = reviewUid\n ? firestore\n .collection('marketplaceListings')\n .doc(listingId)\n .collection('reviews')\n .doc(reviewUid)\n : firestore.collection('marketplaceListings').doc(listingId)\n const targetSnapshot = await target.get()\n if (!targetSnapshot.exists) {\n return Response.json({ error: 'Unknown target' }, { status: 404 })\n }\n // A takedown strips the Verified badge (AGL-1121, decided 2026-08-03).\n //\n // Verified is OUR claim that a human vouched for this publisher. Taking\n // the listing down is us saying the opposite out loud, so the two cannot\n // both stand — a badge surviving a takedown would still be asserting the\n // vouch on the listing page the moment it was restored.\n //\n // Demoted to `listed`, not to `rejected` or `submitted`: the takedown\n // itself is what makes it non-browsable (`hiddenAt`), and rewriting the\n // review verdict would destroy the record of a review that did happen.\n //\n // Restoring deliberately does NOT put the badge back. Re-granting is\n // `verify`, which re-checks the review checklist server-side; an automatic\n // regrant would hand back the badge without anyone re-forming the opinion\n // behind it. Losing it to a takedown is meant to cost a re-review.\n const stripVerified = shouldStripVerifiedOnTakedown({\n action,\n reviewStatus: targetSnapshot.get('reviewStatus'),\n isListingTarget: !reviewUid,\n })\n await target.set(\n reviewUid\n ? { hidden: action === 'hide' }\n : action === 'hide'\n ? {\n hiddenAt: FieldValue.serverTimestamp(),\n hiddenBy: decoded.uid,\n hiddenReason: hideReason,\n ...(stripVerified\n ? { reviewStatus: VERIFIED_STRIPPED_STATUS }\n : {}),\n }\n : {\n hiddenAt: FieldValue.delete(),\n hiddenBy: FieldValue.delete(),\n hiddenReason: FieldValue.delete(),\n },\n { merge: true },\n )\n\n // Takedown means takedown (AGL-948). Hiding a PLUGIN listing also\n // writes the kill switch, so one staff action has one outcome\n // instead of leaving the bundle executing in every workspace that\n // already installed it. The realm join blocks on `hiddenAt` too, but\n // the revocation is what the client-side loaders and the public\n // listing-versions endpoint already understand — belt and braces on\n // the one action where a gap means running attacker code.\n const isPlugin =\n !reviewUid &&\n (targetSnapshot.get('artifactType') === 'plugin' ||\n targetSnapshot.get('type') === 'plugin')\n /**\n * An email starter earns the same treatment for the same reason.\n *\n * It is copied on install, so `hiddenAt` alone reaches only the\n * storefront: every tenant who already installed it goes on MAILING it,\n * from the sending domain every other tenant shares. The revocation is\n * what `emailStarterSendBlock` reads at the send, which is the only\n * chokepoint that can still refuse.\n *\n * The five other copied types are deliberately not here. Their content\n * is rendered on the tenant's own site, where `hiddenAt` blocking the\n * next install is the whole of what a takedown can honestly promise —\n * stopping a page from rendering is a different decision, and one nobody\n * has made.\n */\n const killsInstalledCopies =\n isPlugin ||\n (!reviewUid && targetSnapshot.get('artifactType') === 'emailStarter')\n if (killsInstalledCopies) {\n const revocationRef = firestore.collection('revocations').doc(listingId)\n const current = (await revocationRef.get()).data() as\n | PluginRevocation\n | undefined\n // Both transitions go through the shared helper (AGL-1085) so a\n // takedown and a per-version review revocation can coexist. Restoring\n // used to DELETE the doc whenever it was takedown-owned, which also\n // un-revoked any version a reviewer had stopped for an unrelated\n // reason — `reviewVersions` is what survives the round trip.\n const next = nextRevocationState(current, {\n type: action === 'hide' ? 'takedown' : 'restore',\n })\n if (next) {\n await revocationRef.set(\n {\n ...next,\n ...(action === 'hide' ? { reason: hideReason } : {}),\n revokedBy: decoded.uid,\n revokedAt: FieldValue.serverTimestamp(),\n // A restore drops takedown ownership; the field has to go, not\n // merely be overwritten, or the next restore re-deletes.\n ...(action === 'hide' ? {} : { source: FieldValue.delete() }),\n },\n { merge: true },\n )\n } else if (current) {\n await revocationRef.delete()\n }\n // Make the kill switch reach ALREADY-CACHED pages (AGL-1152). The\n // tenant stamps each plugin node with its revocation state at compose\n // time, so without this the bundle we just killed keeps executing on\n // every cached page until it happens to re-render. Best effort: the\n // tenant refuses a revoked plugin at render time regardless.\n //\n // Plugin-only: it walks the plugin INSTALL PINS, which an email\n // starter has none of, and an email is never part of a cached page —\n // its kill is felt at the send, where nothing is cached.\n if (isPlugin) await dropCachesForListing(firestore, listingId)\n // The offer follows the kill switch here too (AGL-2368). AGL-2306\n // taught the per-version revoke and the reject path to repair the\n // mirror and left this one out, so a takedown flattened `versions` to\n // `'all'` — revoking every build — while `latestApprovedVersion` went\n // on naming one. `hiddenAt` hides the listing from browse and blocks\n // the install route, so nothing was installable through it; but a\n // restore clears `hiddenAt` first and the mirror is what the update\n // badges read, and `nextRevocationState` can return a document that\n // still holds a reviewer's per-version revocations. Recomputed from\n // the versions in both directions rather than reasoned about.\n //\n // Named explicitly rather than reusing `target`: `isPlugin` is only\n // true when `reviewUid` is empty, so they are the same document — but\n // that is a fact two conditions apart, and a repair pointed at a\n // review subdocument would write a `latestApprovedVersion` onto it.\n //\n // Plugin-only, unlike the revocation write above: the mirror is\n // recomputed from `pluginVersions`, a collection no other artifact\n // type has, so running it for an email starter would derive \"nothing\n // approved\" from an empty read and write that over the listing.\n if (isPlugin) {\n await repairLatestApprovedVersion(\n firestore.collection('marketplaceListings').doc(listingId),\n next,\n )\n }\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.takedown.${action}`,\n target: reviewUid\n ? `marketplaceListings/${listingId}/reviews/${reviewUid}`\n : `marketplaceListings/${listingId}`,\n /*\n * A review document is keyed by its AUTHOR's uid, so hiding one is a\n * staff act against a named person. The target names the review, as\n * it must — but on its own that put the takedown nowhere near the\n * page of the person whose words were removed.\n */\n ...(reviewUid ? { subjectUid: reviewUid } : {}),\n after: {\n hidden: action === 'hide',\n ...(hideReason ? { reason: hideReason } : {}),\n ...(killsInstalledCopies ? { revoked: action === 'hide' } : {}),\n // Recorded because it is a side effect of the takedown rather than\n // something the reviewer asked for, and because getting it back is a\n // re-review rather than an undo.\n ...(stripVerified ? { unverified: true } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n return Response.json(\n {\n ok: true,\n hidden: action === 'hide',\n revoked: killsInstalledCopies && action === 'hide',\n // The caller shows this — a badge silently disappearing would be\n // worse than one that never existed.\n unverified: stripVerified,\n },\n { status: 200 },\n )\n }\n\n // Review checklist (AGL-963). Ticks are per {version, sha256} and carry\n // who + when, so \"verified\" is a recorded act rather than a click.\n if (action === 'checklist') {\n const version = String(body?.version ?? '')\n const itemId = String(body?.itemId ?? '')\n const checked = body?.checked !== false\n if (!listingId || !version || !REQUIRED_OR_OPTIONAL.has(itemId)) {\n return Response.json({ error: 'Unknown checklist item' }, { status: 400 })\n }\n const versionRef = firestore\n .collection('marketplaceListings')\n .doc(listingId)\n .collection('pluginVersions')\n .doc(version)\n const versionSnapshot = await versionRef.get()\n if (!versionSnapshot.exists) {\n return Response.json({ error: 'Unknown version' }, { status: 404 })\n }\n await versionRef.set(\n {\n reviewChecklist: {\n [itemId]: checked\n ? {\n by: decoded.uid,\n at: FieldValue.serverTimestamp(),\n // Pins the tick to the bytes it was made against.\n sha256: String(versionSnapshot.get('sha256') ?? ''),\n }\n : FieldValue.delete(),\n },\n },\n { merge: true },\n )\n // Audited (AGL-971): a checklist tick is the record that a human\n // looked, so it needs the same trail as the verdict it unlocks —\n // including WHICH bytes were looked at.\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.checklist.${checked ? 'check' : 'uncheck'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n itemId,\n checked,\n sha256: String(versionSnapshot.get('sha256') ?? ''),\n },\n at: FieldValue.serverTimestamp(),\n })\n return Response.json({ ok: true, itemId, checked }, { status: 200 })\n }\n\n // Per-version verdicts (AGL-966). Approval is a statement about bytes,\n // so it lives on the version doc and installs resolve the newest\n // approved one. Listing-level list/verify still exist, but they can no\n // longer ship code past review on their own.\n if (action === 'approve-version' || action === 'reject-version') {\n const version = String(body?.version ?? '')\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const versionRef = listingRef.collection('pluginVersions').doc(version)\n const versionSnapshot = await versionRef.get()\n if (!versionSnapshot.exists) {\n return Response.json({ error: 'Unknown version' }, { status: 404 })\n }\n // The LISTING has to exist too, and the check belongs up here rather\n // than beside the writes that need it (AGL-1766). A version outliving\n // its listing is not hypothetical — Firestore deletes are not\n // recursive, so `pluginVersions` survives whatever removed the parent.\n //\n // The read below used to be `(await listingRef.get()).data() ?? {}`,\n // and that default was not a convenience: it is what made the two\n // mirrors fire. Both of their conditions are TRUE on `{}` —\n // `!['listed','verified'].includes('')` and `previous == null` — so an\n // absent listing was resurrected as `{ reviewStatus: 'listed' }`, i.e.\n // browsable in the marketplace, from a merge-set. (The third mirror,\n // `latestVersionReviewState`, compares `String(latestVersion ?? '')`\n // against a non-empty `version` and is false on `{}` — it could not\n // fire. The pattern is not uniform even inside one block, which is\n // exactly why AGL-1763 could not express this as a lint rule.)\n //\n // Read BEFORE the verdict write, not after it. Refusing must not\n // discard work that already happened (AGL-1760); refusing here happens\n // before anything has, so the reviewer simply retries against a\n // listing that exists. `?? {}` is gone with it — kept, it would have\n // traded a resurrection for an `update()` rejection served as a 500.\n const listingSnapshot = await listingRef.get()\n if (!listingSnapshot.exists) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n const listing = listingSnapshot.data()\n const sha256 = String(versionSnapshot.get('sha256') ?? '')\n const approving = action === 'approve-version'\n if (approving) {\n const outstanding = outstandingChecklistItems(\n versionSnapshot.get('reviewChecklist'),\n sha256,\n )\n if (outstanding.length) {\n return Response.json(\n {\n error: `Review checklist incomplete — ${outstanding.length} required item(s) outstanding for these bytes`,\n outstanding,\n },\n { status: 409 },\n )\n }\n }\n const reason = String(body?.reason ?? '').slice(0, 500)\n // Structured rejection (AGL-977). The category is what makes rejections\n // comparable across reviewers and queryable afterwards; the comment is\n // what makes one actionable. Requiring only free text gave neither.\n const category = String(body?.category ?? '')\n if (!approving) {\n const invalid = rejectionInputError(category, reason)\n if (invalid) return Response.json({ error: invalid }, { status: 400 })\n }\n await versionRef.set(\n {\n reviewState: approving ? 'approved' : 'rejected',\n reviewedBy: decoded.uid,\n reviewedAt: FieldValue.serverTimestamp(),\n // Records WHICH bytes were approved, so a later republish under\n // the same version string can never inherit this verdict.\n reviewedSha256: sha256,\n grandfathered: FieldValue.delete(),\n ...(approving\n ? {\n // Clear a previous rejection's fields on approval, or a\n // version that was rejected and then approved keeps\n // explaining why it was turned down.\n reviewRejectionReason: FieldValue.delete(),\n reviewRejectionCategory: FieldValue.delete(),\n }\n : {\n reviewRejectionReason: reason,\n reviewRejectionCategory: category,\n // REALM TRUST IS WITHDRAWN WITH THE APPROVAL (AGL-2306).\n //\n // `sign-plugin` refuses to grant `trust: 'realm'` unless the\n // version is approved — approval gates the grant. Nothing\n // ungated it: the realm load path checks `hiddenAt`, the sha,\n // the signature and the revocation, and never re-reads\n // `reviewState`. So approve → sign → re-review → reject left\n // the version loading IN THE APP REALM, where neither the\n // sandbox iframe nor the plugin-origin CSP is between it and\n // user data, until staff separately reached for the kill\n // switch.\n //\n // The same four fields `sign-plugin`'s own revoke branch\n // clears, so there is one shape of \"untrusted\" rather than\n // two. This does NOT stop the bundle running as a sandboxed\n // plugin — that is what the per-version revocation beside\n // this decision is for, and it is deliberately a separate\n // choice (a thin README is the usual rejection, and an\n // unannounced site outage is worse). It withdraws only the\n // privilege that approval was the precondition for.\n trust: FieldValue.delete(),\n signature: FieldValue.delete(),\n trustGrantedBy: FieldValue.delete(),\n trustGrantedAt: FieldValue.delete(),\n }),\n },\n { merge: true },\n )\n\n // A plugin with its first approved version becomes browsable. Later\n // approvals never change listing status — that is the point: an\n // update is reviewed without disturbing what customers already have.\n //\n // The three mirrors below write through `updateExisting` as the second\n // line for the window the check above cannot close — a listing deleted\n // mid-handler. Every payload here is FLAT with no delete sentinel, so\n // the switch is semantically identical to the merge-set it replaces;\n // the `false` return needs no branch, because a listing that is gone by\n // now wants nothing mirrored onto it.\n\n // Mirror this verdict onto the listing for the marketplace (AGL-1121),\n // but ONLY when it is the newest version. Approving an old version\n // must not let the listing claim its newest bytes were reviewed —\n // which is the exact shape of the bug this mirror exists to fix.\n if (String(listing.latestVersion ?? '') === version) {\n await updateExisting(listingRef, {\n latestVersionReviewState: approving ? 'approved' : 'rejected',\n })\n }\n if (\n approving &&\n !['listed', 'verified'].includes(String(listing.reviewStatus ?? ''))\n ) {\n await updateExisting(listingRef, {\n reviewStatus: 'listed',\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n\n // Denormalise the newest approved version onto the listing (AGL-1016).\n // `pluginVersions` is server-only, so a console showing \"update\n // available\" has nothing else to read — and reading `latestVersion`\n // instead would advertise a version the install route refuses, leaking\n // AGL-966's guarantee back out through a badge.\n //\n // Only ever moves forward: approving an older version after a newer one\n // is a real sequence (a reviewer working through a backlog) and must not\n // walk the offer backwards.\n if (approving) {\n const previous = listing.latestApprovedVersion\n if (\n previous == null ||\n (compareArtifactVersions(String(previous), version) ?? 0) < 0\n ) {\n await updateExisting(listingRef, {\n latestApprovedVersion: version,\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n } else if (String(listing.latestApprovedVersion ?? '') === version) {\n // …and BACK when the version being offered is the one just rejected\n // (AGL-2306). Nothing did this, so a re-review that turned a live\n // version down left the listing advertising it — an \"Update to vX\"\n // for bytes `install-plugin` answers 409 to.\n const revocation = (\n await firestore.collection('revocations').doc(listingId).get()\n ).data() as PluginRevocation | undefined\n await repairLatestApprovedVersion(listingRef, revocation)\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.version.${approving ? 'approve' : 'reject'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n sha256,\n ...(reason ? { reason } : {}),\n // Both, not one (AGL-971 + AGL-977): the category is what an audit\n // can be counted by, the comment is what makes a single row make\n // sense to a human reading it later.\n ...(category ? { category } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n // Pins sitting on these exact bytes right now (AGL-1085). Rejecting a\n // version does NOT stop it — the runtime resolves a pin by\n // {version, sha256} and only asks whether it is revoked — so both\n // sides have to be told, and the reviewer needs the number before\n // deciding whether to reach for the kill switch.\n const liveInstalls = Number(versionSnapshot.get('activeInstalls') ?? 0)\n const stranded = !approving && liveInstalls > 0\n\n if (listing.profileId) {\n await notifyOrgAdmins(String(listing.profileId), {\n type: 'marketplace.review',\n title: approving\n ? `\"${listing.displayName}\" v${version} approved`\n : `\"${listing.displayName}\" v${version} was not approved`,\n body: approving\n ? 'It is now the version new installs receive.'\n : stranded\n ? `${reason}\\n\\nThis version is still installed on ` +\n `${liveInstalls} site${liveInstalls === 1 ? '' : 's'}. ` +\n 'Rejecting it does not remove it — uninstall or roll back.'\n : reason,\n orgId: String(listing.profileId),\n link: '/',\n }).catch(() => undefined)\n await emailPublisher(\n String(listing.profileId),\n approving\n ? `${listing.displayName} v${version} passed review`\n : `${listing.displayName} v${version} was not approved`,\n approving\n ? `Your plugin version ${version} has been approved and is now ` +\n 'the version new installs receive. Existing installs stay on ' +\n 'the version they pinned until their site owners upgrade.'\n : `Your plugin version ${version} was not approved.\\n\\n` +\n `Reason: ${reason}\\n\\nPublishing a new version puts it back ` +\n 'in the review queue. The previously approved version, if any, ' +\n 'keeps installing in the meantime.' +\n (stranded\n ? `\\n\\nNote: v${version} is still installed on ` +\n `${liveInstalls} site${liveInstalls === 1 ? '' : 's'}. ` +\n 'A rejection stops new installs, it does not remove an ' +\n 'existing one — uninstall it or roll back to an approved ' +\n 'version.'\n : ''),\n )\n }\n\n return Response.json(\n {\n ok: true,\n version,\n reviewState: approving ? 'approved' : 'rejected',\n // Lets the reviewer's confirmation say what it actually did, and\n // offer the kill switch when the bytes are live somewhere.\n liveInstalls,\n stranded,\n },\n { status: 200 },\n )\n }\n\n // Per-version kill switch (AGL-1085). Until now a reviewer's only way to\n // stop live bytes was a listing-wide takedown, which also revokes the\n // approved version customers are happily running and hides the listing.\n // Rejection deliberately stays a verdict rather than a kill: most\n // rejections are a thin README, and an unannounced site outage is worse\n // than the gap. This is the deliberate, adjacent action.\n //\n // This does NOT strip the Verified badge, unlike a takedown (AGL-1121).\n // The two claims are scoped differently and the split is the whole point:\n // Verified says a human vouched for the PUBLISHER and survives version\n // bumps, while the separate \"Reviewed\" chip speaks for THESE bytes and is\n // re-earned per version. Stripping the publisher claim for one bad release\n // would punish an honest mistake, and is not reversible without a full\n // re-review. A takedown is the action that contradicts the publisher claim,\n // and that one does strip it.\n //\n // That reasoning only holds because the BYTES claim is withdrawn instead —\n // which it now is, below. It was not before, and the gap is what made\n // keeping the badge unsafe rather than merely debatable.\n if (action === 'revoke-version' || action === 'unrevoke-version') {\n const version = String(body?.version ?? '')\n if (!listingId || !version) {\n return Response.json(\n { error: 'Listing and version required' },\n { status: 400 },\n )\n }\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const listing = (await listingRef.get()).data() ?? {}\n const revocationRef = firestore.collection('revocations').doc(listingId)\n const current = (await revocationRef.get()).data() as\n | PluginRevocation\n | undefined\n const revoking = action === 'revoke-version'\n const next = nextRevocationState(current, {\n type: revoking ? 'revoke-version' : 'unrevoke-version',\n version,\n })\n if (next) {\n await revocationRef.set(\n {\n ...next,\n reason: String(body?.reason ?? current?.reason ?? '').slice(0, 500),\n revokedBy: decoded.uid,\n revokedAt: FieldValue.serverTimestamp(),\n },\n { merge: true },\n )\n } else {\n await revocationRef.delete()\n }\n // Same reach as the takedown path above (AGL-1152): a per-version\n // revocation changes what every cached page renders, and nothing else\n // drops that HTML.\n await dropCachesForListing(firestore, listingId)\n\n // Withdraw the \"Reviewed\" chip when the bytes we just killed are the ones\n // customers are being offered (AGL-1121).\n //\n // This was ASSUMED to happen already and did not. `latestVersionReviewState`\n // is written only by approve/reject and on publish, so a version approved\n // and later revoked kept `'approved'` — and since a per-version revocation\n // deliberately does NOT hide the listing (that is the whole difference from\n // a takedown), the marketplace went on showing \"A human at Aglyn read these\n // exact bytes\" about bytes we had just stopped from executing. Revocation\n // is not surfaced anywhere else in the browse or listing UI either, so\n // nothing contradicted it.\n //\n // `revoked` rather than `rejected`: it was not turned down in review, it\n // was killed afterwards, and the audit trail should not blur those. Both\n // consumers test against `'approved'`, so this correctly drops the chip and\n // raises the caution alert.\n //\n // Only when it is the LATEST version, because that is what both consumers\n // describe. Revoking an old version says nothing about what is on offer.\n const isLatest = revocationWithdrawsReviewedClaim({\n revokedVersion: version,\n latestVersion: String(listing['latestVersion'] ?? ''),\n })\n if (isLatest) {\n const versionSnapshot = await listingRef\n .collection('pluginVersions')\n .doc(version)\n .get()\n await listingRef.set(\n {\n latestVersionReviewState: revoking\n ? REVOKED_VERSION_REVIEW_STATE\n : // Restoring returns it to whatever the version's own verdict\n // says, rather than assuming `approved` — un-revoking a version\n // that was never approved must not promote it.\n String(versionSnapshot.get('reviewState') ?? 'pending'),\n },\n { merge: true },\n )\n }\n\n // The offer follows the kill switch (AGL-2306). A revoked version is\n // refused by `install-plugin`, so leaving it as `latestApprovedVersion`\n // advertises an update that cannot be taken; un-revoking restores it.\n // Both directions, because both change what is installable.\n await repairLatestApprovedVersion(listingRef, next)\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.revocation.${revoking ? 'revoke' : 'restore'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n versions: next?.versions ?? null,\n ...(isLatest ? { latestVersionReviewStateChanged: true } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n if (listing.profileId) {\n await notifyOrgAdmins(String(listing.profileId), {\n type: 'marketplace.review',\n title: revoking\n ? `\"${listing.displayName}\" v${version} was stopped`\n : `\"${listing.displayName}\" v${version} was allowed to run again`,\n body: revoking\n ? 'It has been disabled on every site running it. Sites showing ' +\n 'this plugin now render a placeholder.'\n : 'Sites running it are no longer blocked.',\n orgId: String(listing.profileId),\n link: '/',\n }).catch(() => undefined)\n }\n\n return Response.json(\n { ok: true, version, revoked: revoking },\n { status: 200 },\n )\n }\n\n // Declining a verification request (AGL-1217). Handled before the ACTIONS\n // lookup because it deliberately has NO `reviewStatus` to move to: the\n // listing stays exactly as live as it was. Refusing a badge is not a\n // verdict on the code, and routing it through the status ladder would\n // make it one.\n if (action === 'decline-verification') {\n const declineReason = String(body?.reason ?? '').trim().slice(0, 500)\n if (!listingId) {\n return Response.json({ error: 'Unknown action' }, { status: 400 })\n }\n // Required, unlike most fields here. The publisher is notified of this\n // and then has to wait out a cooldown before asking again; \"no, and we\n // will not say why, try in a month\" is not a usable answer.\n if (!declineReason) {\n return Response.json(\n { error: 'A reason is required — the publisher is told it' },\n { status: 400 },\n )\n }\n const listingRef = firestore\n .collection('marketplaceListings')\n .doc(listingId)\n const listing = (await listingRef.get()).data()\n if (!listing) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n if (listing.verificationRequest?.state !== 'pending') {\n return Response.json(\n { error: 'No verification request is waiting' },\n { status: 409 },\n )\n }\n await listingRef.set(\n {\n verificationRequest: {\n ...listing.verificationRequest,\n state: 'declined',\n decidedAt: FieldValue.serverTimestamp(),\n decidedBy: decoded.uid,\n declineReason,\n },\n },\n { merge: true },\n )\n /*\n * THE AUDIT ROW THIS BRANCH NEVER WROTE (AGL-2328).\n *\n * Every sibling branch in this file audits, and the file header at the\n * top claims the route is audited. This one mutated\n * `verificationRequest.state`, notified the publisher and started a\n * cooldown, and left no record — so a decline was the one staff\n * decision here that could not be reviewed afterwards, on the action\n * whose reason staff are REQUIRED to type.\n *\n * `reason` uses the audit log's own reason column rather than being\n * buried in `after`, because the audit page renders and exports that\n * column and searches it (AGL-1652) — a why nobody can filter on is a\n * why nobody reads.\n */\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n actorEmail: decoded.email ? String(decoded.email) : null,\n action: 'plugins.verification.decline',\n scope: 'marketplace',\n target: `marketplaceListings/${listingId}`,\n before: { verificationState: 'pending' },\n after: {\n verificationState: 'declined',\n cooldownDays: VERIFICATION_DECLINE_COOLDOWN_DAYS,\n },\n reason: declineReason,\n at: FieldValue.serverTimestamp(),\n })\n\n const publisherOrgId = String(listing.profileId ?? '')\n if (publisherOrgId) {\n await notifyOrgAdmins(publisherOrgId, {\n type: 'marketplace.review',\n title: `Verification declined for \"${listing.displayName}\"`,\n // Says plainly that nothing about the listing changed. Without it a\n // publisher reads \"declined\" as a takedown of the plugin itself.\n body:\n `${declineReason}\\n\\nYour plugin is unaffected and stays listed. ` +\n `You can request verification again in ` +\n `${VERIFICATION_DECLINE_COOLDOWN_DAYS} days.`,\n orgId: publisherOrgId,\n link: '/',\n }).catch(() => undefined)\n }\n return Response.json({ ok: true, state: 'declined' }, { status: 200 })\n }\n\n const nextStatus = ACTIONS[action]\n if (!listingId || !nextStatus) {\n return Response.json({ error: 'Unknown action' }, { status: 400 })\n }\n const reason = String(body?.reason ?? '').slice(0, 500)\n const category = String(body?.category ?? '')\n if (action === 'reject') {\n const invalid = rejectionInputError(category, reason)\n if (invalid) return Response.json({ error: invalid }, { status: 400 })\n }\n\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const listing = (await listingRef.get()).data()\n if (!listing) return Response.json({ error: 'Unknown listing' }, { status: 404 })\n\n // Both gates that expose a plugin to customers require a completed\n // checklist (AGL-963).\n //\n // `list` matters MORE than `verify`, which is easy to get backwards:\n // listing is what makes `isListingBrowsable` true, so it is the moment\n // executable third-party code becomes installable by every workspace.\n // `verify` only adds the badge on top. Gating the badge while leaving\n // listing open would put the ceremony on the weaker action.\n //\n // `start-review` and `reject` stay ungated on purpose: a reviewer must\n // be able to throw something out without first ticking eight boxes\n // about a bundle they have already decided against.\n if (action === 'verify' || action === 'list') {\n const version = String(listing.latestVersion ?? '')\n const versionSnapshot = await listingRef\n .collection('pluginVersions')\n .doc(version)\n .get()\n const outstanding = outstandingChecklistItems(\n versionSnapshot.get('reviewChecklist'),\n String(versionSnapshot.get('sha256') ?? ''),\n )\n if (outstanding.length) {\n return Response.json(\n {\n error: `Review checklist incomplete — ${outstanding.length} required item(s) outstanding`,\n outstanding,\n },\n { status: 409 },\n )\n }\n }\n\n await listingRef.set(\n {\n reviewStatus: nextStatus,\n reviewedBy: decoded.uid,\n reviewedAt: FieldValue.serverTimestamp(),\n // Granting the badge answers any request that was waiting (AGL-1217).\n // Left alone it would sit `pending` forever, so the staff queue would\n // keep offering a decision on a listing that already has the badge,\n // and the publisher's button would stay disabled as \"already pending\"\n // with nothing to wait for.\n //\n // Only when something is actually waiting: a `verify` on a listing\n // nobody asked about must not invent a request that was never made.\n ...(action === 'verify' &&\n listing.verificationRequest?.state === 'pending'\n ? {\n verificationRequest: {\n ...listing.verificationRequest,\n state: 'granted',\n decidedAt: FieldValue.serverTimestamp(),\n decidedBy: decoded.uid,\n },\n }\n : {}),\n ...(action === 'reject'\n ? { rejectionReason: reason, rejectionCategory: category }\n : {\n rejectionReason: FieldValue.delete(),\n rejectionCategory: FieldValue.delete(),\n }),\n },\n { merge: true },\n )\n\n // Tell the publisher their listing moved (rejections especially).\n if (\n listing.profileId &&\n ['reject', 'list', 'verify', 'delist'].includes(action)\n ) {\n // Publishers are ORGS now (AGL-652), so `profileId` is an org id —\n // writing to users/{profileId}/notifications silently dropped every\n // verdict into a user document nobody reads. Notify the org's managers.\n const publisherOrgId = String(listing.profileId ?? '')\n const publisherSlug = publisherOrgId\n ? ((\n await firestore.collection('orgs').doc(publisherOrgId).get()\n ).get('slug') as string | undefined)\n : undefined\n if (publisherOrgId) {\n await notifyOrgAdmins(publisherOrgId, {\n type: 'marketplace.review',\n title:\n action === 'reject'\n ? `\"${listing.displayName}\" was rejected`\n : action === 'delist'\n ? `\"${listing.displayName}\" is back in review`\n : `\"${listing.displayName}\" is now ${nextStatus}`,\n body:\n action === 'reject'\n ? // Category, then what to do about it, then the reviewer's own\n // words (AGL-977). The publisher's first question is \"what do\n // I fix\" — a bare comment answered that only as well as the\n // reviewer happened to write it.\n [\n pluginRejectionCategory(category)?.label,\n pluginRejectionCategory(category)?.guidance,\n reason,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n : action === 'delist'\n ? reason ||\n 'It has been removed from the marketplace while we take ' +\n 'another look. Existing installs keep working.'\n : 'Your plugin passed review.',\n orgId: publisherOrgId,\n link: publisherSlug\n ? buildRoute(Route.ORG_MARKETPLACE, {\n orgSlug: publisherSlug,\n })\n : '/',\n }).catch(() => undefined)\n await emailPublisher(\n publisherOrgId,\n action === 'reject'\n ? `${listing.displayName} was rejected — ${rejectionHeadline(\n category,\n reason,\n )}`\n : action === 'delist'\n ? `${listing.displayName} was removed from the marketplace`\n : `${listing.displayName} is now ${nextStatus}`,\n action === 'reject' || action === 'delist'\n ? reason ||\n 'It has been removed from the marketplace while we take ' +\n 'another look. Existing installs keep working.'\n : 'Your plugin passed review and is live in the marketplace.',\n )\n }\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.${action}`,\n target: `marketplaceListings/${listingId}`,\n after: { reviewStatus: nextStatus, ...(reason ? { reason } : {}) },\n at: FieldValue.serverTimestamp(),\n })\n\n return Response.json({ ok: true, reviewStatus: nextStatus }, { status: 200 })\n } catch (error) {\n // An unverifiable credential is a 401, not a fault of ours\n // (AGL-1993). Null for anything else, so a real failure keeps its 500.\n const unauthenticated = invalidIdTokenResponse(error)\n if (unauthenticated) return unauthenticated\n console.error(error)\n return Response.json({ error: 'Review action failed' }, { status: 500 })\n }\n}\n\nexport { handler as marketplaceAdminReviews }\n"],"names":["REVOKED_VERSION_REVIEW_STATE","revocationWithdrawsReviewedClaim","shouldStripVerifiedOnTakedown","VERIFIED_STRIPPED_STATUS","checkPluginBundle","isPluginRevoked","newestInstallableVersion","isStoredVerdictCurrent","nextRevocationState","PLUGIN_HOST_ABI_VERSION","PLUGIN_VERIFIER_VERSION","pluginArtifactPath","pluginRequestFromWeb","readPluginContributions","emailUnverifiedResponse","findUserByUidAcrossPools","firebaseAdmin","isImpersonationSession","updateExisting","invalidIdTokenResponse","buildRoute","compareArtifactVersions","Route","outstandingChecklistItems","PLUGIN_REVIEW_CHECKLIST","pluginRejectionCategory","rejectionHeadline","rejectionInputError","attestationsForBytes","VERIFICATION_DECLINE_COOLDOWN_DAYS","PUBLISHER_AGREEMENT_VERSION","publisherAgreementState","FieldValue","notifyOrgAdmins","emailPublisher","dropCachesForListing","REQUIRED_OR_OPTIONAL","Set","map","item","id","ACTIONS","list","verify","reject","delist","unverify","listingDetail","firestore","listingId","requestedVersion","listing","versions","attestationEntries","acceptance","listingRef","collection","doc","snapshot","get","data","Response","json","error","status","versionsSnapshot","orderBy","limit","docs","publishedAt","version","String","trust","sha256","hostAbi","Number","capabilities","contributes","elements","toDate","toISOString","installCount","activeInstalls","signed","Boolean","repositoryUrl","reviewState","grandfathered","verification","reviewChecklist","publisherAttestation","publisherId","profileId","publisher","publisherProfile","revocation","pendingFirst","reverse","find","entry","reviewVersion","latestVersion","artifactsBucket","process","env","PLUGIN_ARTIFACTS_BUCKET","reviewEntry","reviewSha","stored","storedIsCurrent","verifier","ok","problems","checks","verifierCached","bytes","app","storage","bucket","file","download","result","toString","declaredNetwork","Array","isArray","network","origin","declaredContributions","set","verifierVersion","checkedAt","serverTimestamp","merge","catch","undefined","Object","values","filter","attesterUid","by","attestedAt","at","attestedBy","found","record","email","displayName","description","verificationRequest","state","requestedAt","declineReason","readme","license","categories","homepageUrl","publisherName","publisherSlug","reviewStatus","rejectionReason","rejectionCategory","priceUsd","hidden","hiddenAt","hiddenReason","revoked","revokedVersions","unpublished","deletedAt","private","visibility","platformHostAbi","checklist","fromEntries","entries","checklistOutstanding","attestation","publisherAgreement","acceptedAt","required","repairLatestApprovedVersion","newest","latestApprovedVersion","delete","updatedAt","handler","request","headers","method","body","query","rawHeaders","authorization","idToken","startsWith","slice","length","decoded","auth","verifyIdToken","email_verified","detailId","where","rows","Promise","all","latest","ref","latestReviewState","queue","row","verificationRequests","listedSnapshot","includes","listed","versionDoc","pendingVersions","realmVersions","versionCount","publisherIds","publishers","getAll","exists","action","hideReason","reason","trim","reviewUid","target","targetSnapshot","stripVerified","isListingTarget","hiddenBy","uid","isPlugin","killsInstalledCopies","revocationRef","current","next","type","revokedBy","revokedAt","source","add","actorUid","subjectUid","after","unverified","versionSnapshot","itemId","checked","has","versionRef","listingSnapshot","approving","outstanding","category","invalid","reviewedBy","reviewedAt","reviewedSha256","reviewRejectionReason","reviewRejectionCategory","signature","trustGrantedBy","trustGrantedAt","latestVersionReviewState","previous","liveInstalls","stranded","title","orgId","link","revoking","isLatest","revokedVersion","latestVersionReviewStateChanged","decidedAt","decidedBy","actorEmail","scope","before","verificationState","cooldownDays","publisherOrgId","nextStatus","label","guidance","join","ORG_MARKETPLACE","orgSlug","unauthenticated","console","marketplaceAdminReviews"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,4BAA4B,EAC5BC,gCAAgC,EAChCC,6BAA6B,EAC7BC,wBAAwB,QACnB,mCAA+B;AACtC,SACEC,iBAAiB,EACjBC,eAAe,EACfC,wBAAwB,EACxBC,sBAAsB,EACtBC,mBAAmB,EACnBC,uBAAuB,EACvBC,uBAAuB,EACvBC,kBAAkB,EAClBC,oBAAoB,EACpBC,uBAAuB,QAGlB,sBAAqB;AAC5B,SACEC,uBAAuB,EACvBC,wBAAwB,EACxBC,aAAa,EACbC,sBAAsB,EACtBC,cAAc,QACT,2BAA0B;AACjC,SAASC,sBAAsB,QAAQ,mDAAkD;AACzF,SACEC,UAAU,EACVC,uBAAuB,EACvBC,KAAK,QACA,sBAAqB;AAC5B,SACEC,yBAAyB,EACzBC,uBAAuB,QAClB,sCAAkC;AACzC,SACEC,uBAAuB,EACvBC,iBAAiB,EACjBC,mBAAmB,QACd,0CAAsC;AAC7C,SAASC,oBAAoB,QAAQ,+CAA8C;AACnF,SAASC,kCAAkC,QAAQ,kDAAiD;AACpG,SACEC,2BAA2B,EAC3BC,uBAAuB,QAClB,6CAA4C;AACnD,SAASC,UAAU,QAAQ,2BAA0B;AACrD,SAASC,eAAe,QAAQ,2BAA0B;AAC1D;;;;;CAKC,GACD,SAASC,cAAc,QAAQ,8BAA0B;AACzD,SAASC,oBAAoB,QAAQ,yBAAqB;AAE1D;;;;;;;;;;;;;;;CAeC,GACD,wDAAwD,GACxD,MAAMC,uBAAuB,IAAIC,IAC/Bb,wBAAwBc,GAAG,CAAC,CAACC,OAASA,KAAKC,EAAE;AAG/C,MAAMC,UAAkC;IACtC,gBAAgB;IAChBC,MAAM;IACNC,QAAQ;IACRC,QAAQ;IACR,oEAAoE;IACpE,wEAAwE;IACxE,sEAAsE;IACtE,wEAAwE;IACxE,wEAAwE;IACxE,qEAAqE;IACrEC,QAAQ;IACRC,UAAU;AACZ;AAEA;;;;;CAKC,GACD,eAAeC,cACbC,SAAsC,EACtCC,SAAiB,EACjBC,gBAAyB;QAmDEC,oBA0ClBA,mDAqGQA,sBACAA,sBAMOA,2CAICA,4CAGbA,iBACCA,kBACGA,qBACCA,oCAUCA,uBACGA,0BACEA,4BACFA,mBACKA,yBAICA,yBAEFA;QA5IrBC,gBAgFgBC,0BAElBA,oCAAAA,qCAAAA,6BAAAA,2BA8BUF,iDAAAA,kDAAAA,0CA4FMG,+BAAAA,gCAAAA;IArSlB,MAAMC,aAAaP,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR;IACnE,MAAMS,WAAW,MAAMH,WAAWI,GAAG;IACrC,MAAMR,UAAUO,SAASE,IAAI;IAC7B,IAAI,CAACT,SAAS;QACZ,OAAOU,SAASC,IAAI,CAAC;YAAEC,OAAO;QAAkB,GAAG;YAAEC,QAAQ;QAAI;IACnE;IAEA,MAAMC,mBAAmB,MAAMV,WAC5BC,UAAU,CAAC,kBACXU,OAAO,CAAC,eAAe,QACvBC,KAAK,CAAC,IACNR,GAAG;IACN,MAAMP,WAAWa,iBAAiBG,IAAI,CAAC9B,GAAG,CAAC,CAACmB;YAGxBA,UACTA,WACQA,WAEDA,WAGD5C,0BAKH4C,iBAKWA,WACEA,WAIDA,WACFA,WAINA,WACGA,YACKA;YAhBTY,qBAAAA;QAff,MAAMA,cAAcZ,IAAIE,GAAG,CAAC;QAC5B,OAAO;YACLW,SAASC,QAAOd,WAAAA,IAAIE,GAAG,CAAC,sBAARF,WAAsBA,IAAIjB,EAAE;YAC5CgC,KAAK,GAAEf,YAAAA,IAAIE,GAAG,CAAC,oBAARF,YAAoB;YAC3BgB,QAAQF,QAAOd,YAAAA,IAAIE,GAAG,CAAC,qBAARF,YAAqB;YACpCiB,SAASC,OAAOlB,IAAIE,GAAG,CAAC,wBAAwB;YAChDiB,YAAY,GAAEnB,YAAAA,IAAIE,GAAG,CAAC,oCAARF,YAAoC,CAAC;YACnD,uEAAuE;YACvE,6DAA6D;YAC7DoB,WAAW,GAAEhE,2BAAAA,wBAAwB4C,IAAIE,GAAG,CAAC,oCAAhC9C,2BAA4D;YACzE,uEAAuE;YACvE,mEAAmE;YACnE,sEAAsE;YACtE,kEAAkE;YAClEiE,QAAQ,GAAErB,YAAAA,IAAIE,GAAG,CAAC,gCAARF,YAAgC,EAAE;YAC5CY,WAAW,UAAEA,gCAAAA,uBAAAA,YAAaU,MAAM,sBAAnBV,sBAAAA,0BAAAA,iCAAAA,oBAAyBW,WAAW,qBAAM;YACvD,uEAAuE;YACvE,uEAAuE;YACvE,kDAAkD;YAClDC,cAAcN,QAAOlB,YAAAA,IAAIE,GAAG,CAAC,2BAARF,YAA2B;YAChDyB,gBAAgBP,QAAOlB,YAAAA,IAAIE,GAAG,CAAC,6BAARF,YAA6B;YACpD0B,QAAQC,QAAQ3B,IAAIE,GAAG,CAAC;YACxB,sEAAsE;YACtE,qCAAqC;YACrC0B,eAAed,QAAOd,YAAAA,IAAIE,GAAG,CAAC,4BAARF,YAA4B;YAClD6B,aAAaf,QAAOd,YAAAA,IAAIE,GAAG,CAAC,0BAARF,YAA0B;YAC9C8B,eAAeH,QAAQ3B,IAAIE,GAAG,CAAC;YAC/B,oEAAoE;YACpE,qDAAqD;YACrD6B,YAAY,GAAE/B,YAAAA,IAAIE,GAAG,CAAC,2BAARF,YAA2B;YACzCgC,eAAe,GAAEhC,aAAAA,IAAIE,GAAG,CAAC,8BAARF,aAA8B;YAC/CiC,oBAAoB,GAAEjC,aAAAA,IAAIE,GAAG,CAAC,mCAARF,aAAmC;QAC3D;IACF;IAEA,qEAAqE;IACrE,MAAMkC,cAAcpB,QAAOpB,qBAAAA,QAAQyC,SAAS,YAAjBzC,qBAAqB;IAChD,MAAM0C,YAAYF,cACd,MAAM3C,UAAUQ,UAAU,CAAC,QAAQC,GAAG,CAACkC,aAAahC,GAAG,KACvD;IAEJ,sEAAsE;IACtE,yEAAyE;IACzE,2EAA2E;IAC3E,gDAAgD;IAChD,MAAMmC,mBAAmBH,cACrB,MAAM3C,UAAUQ,UAAU,CAAC,qBAAqBC,GAAG,CAACkC,aAAahC,GAAG,KACpE;IACJ,MAAML,aAAawC,oCAAAA,iBAAkBnC,GAAG,CAAC;IAIzC,0EAA0E;IAC1E,wCAAwC;IACxC,MAAMoC,aAAa,AACjB,CAAA,MAAM/C,UAAUQ,UAAU,CAAC,eAAeC,GAAG,CAACR,WAAWU,GAAG,EAAC,EAC7DC,IAAI;IAEN,sEAAsE;IACtE,qDAAqD;IACrD,EAAE;IACF,gEAAgE;IAChE,yEAAyE;IACzE,iEAAiE;IACjE,yEAAyE;IACzE,qEAAqE;IACrE,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,uEAAuE;IACvE,oDAAoD;IACpD,MAAMoC,eAAe;WAAI5C;KAAS,CAC/B6C,OAAO,GACPC,IAAI,CAAC,CAACC,QAAUA,MAAMb,WAAW,KAAK;IACzC,MAAMc,gBACJ,AAAClD,sBACCE,iBAAAA,SAAS8C,IAAI,CAAC,CAACC,QAAUA,MAAM7B,OAAO,KAAKpB,sCAA3CE,eAA8DkB,OAAO,MACvE0B,gCAAAA,aAAc1B,OAAO,KACrBC,QAAOpB,yBAAAA,QAAQkD,aAAa,YAArBlD,yBAAyB;IAClC,MAAMmD,kBAAkBC,QAAQC,GAAG,CAACC,uBAAuB;IAC3D,MAAMC,cAActD,SAAS8C,IAAI,CAAC,CAACC,QAAUA,MAAM7B,OAAO,KAAK8B;IAC/D,MAAMO,YAAYD,+BAAAA,YAAajC,MAAM;IACrC,MAAMmC,SAASF,+BAAAA,YAAalB,YAAY;IACxC,MAAMqB,kBAAkBtG,uBAAuBqG,QAAQD,oBAAAA,YAAa;IAEpE,IAAIG,WAAoBD,kBACpB;QACEE,EAAE,EAAEH,0BAAAA,OAAQG,EAAE;QACdC,QAAQ,UAAEJ,0BAAAA,OAAQI,QAAQ,mBAAI,EAAE;QAChC,qEAAqE;QACrE,iEAAiE;QACjE,sCAAsC;QACtCC,MAAM,WAAEL,0BAAAA,OAAQK,MAAM,oBAAI,EAAE;IAC9B,IACA;IACJ,IAAIC,iBAAiBL;IACrB,IAAI,CAACA,mBAAmBP,mBAAmBK,WAAW;QACpD,IAAI;;gBAW+BD;YAVjC,MAAM,CAACS,MAAM,GAAG,MAAMnG,cACnBoG,GAAG,GACHC,OAAO,GACPC,MAAM,CAAChB,iBACPiB,IAAI,CAAC5G,mBAAmBsC,WAAWmD,eAAeO,YAClDa,QAAQ;YACX,mEAAmE;YACnE,sEAAsE;YACtE,iEAAiE;YACjE,MAAMC,SAASrH,kBAAkB+G,MAAMO,QAAQ,CAAC,SAAS;gBACvDC,iBAAiBC,MAAMC,OAAO,CAACnB,gCAAAA,4BAAAA,YAAa9B,YAAY,qBAAzB8B,0BAA2BoB,OAAO,IAC7DpB,YAAY9B,YAAY,CAACkD,OAAO,CAACxF,GAAG,CAAC,CAACyF,SACpCxD,OAAOwD,WAET,EAAE;gBACN,oEAAoE;gBACpE,oEAAoE;gBACpE,wBAAwB;gBACxBC,qBAAqB,YAAEtB,+BAAAA,YAAa7B,WAAW,qBAAI;YACrD;YACAiC,WAAWW;YACX,qEAAqE;YACrE,qEAAqE;YACrE,kEAAkE;YAClE,sEAAsE;YACtE,wCAAwC;YACxC,MAAMlE,WACHC,UAAU,CAAC,kBACXC,GAAG,CAAC2C,eACJ6B,GAAG,CACF;gBACEzC,cAAc;oBACZuB,IAAIU,OAAOV,EAAE;oBACbC,UAAUS,OAAOT,QAAQ;oBACzBC,QAAQQ,OAAOR,MAAM;oBACrBxC,QAAQkC;oBACRuB,iBAAiBxH;oBACjByH,WAAWnG,WAAWoG,eAAe;gBACvC;YACF,GACA;gBAAEC,OAAO;YAAK,GAEfC,KAAK,CAAC,IAAMC;QACjB,EAAE,eAAM;YACNzB,WAAW;gBAAE/C,OAAO;YAAuB;YAC3CmD,iBAAiB;QACnB;IACF;IAEA,2EAA2E;IAC3E,uEAAuE;IACvE,yEAAyE;IACzE,MAAM7D,qBAAqBmF,OAAOC,MAAM,UACrC/B,+BAAAA,YAAahB,oBAAoB,oBAAI,CAAC,GAIvCgD,MAAM,CAAC,CAACvC,QAAUA,CAAAA,yBAAAA,MAAO1B,MAAM,MAAKkC;IACtC,MAAMgC,eAActF,2BAAAA,mBAAmB6C,IAAI,CAAC,CAACC,QAAUA,MAAMyC,EAAE,sBAA3CvF,yBAA8CuF,EAAE;IACpE,MAAMC,uBACJxF,4BAAAA,mBAAmB6C,IAAI,CAAC,CAACC,QAAUA,MAAM2C,EAAE,uBAA3CzF,8BAAAA,0BAA8CyF,EAAE,sBAAhDzF,sCAAAA,4BAAkD0B,MAAM,sBAAxD1B,qCAAAA,yCAAAA,iDAAAA,mCAA8D2B,WAAW,sBACzE;IACF,IAAI+D,aAA4BJ,sBAAAA,cAAe;IAC/C,IAAIA,aAAa;QACf,IAAI;YACF,yEAAyE;YACzE,yEAAyE;YACzE,sEAAsE;YACtE,MAAMK,QAAQ,MAAMjI,yBAAyB4H;YAC7C,IAAIK,OAAO;oBAEPA,QAAAA;gBADFD,cACEC,UAAAA,sBAAAA,MAAMC,MAAM,CAACC,KAAK,YAAlBF,sBAAsBA,MAAMC,MAAM,CAACE,WAAW,YAA9CH,SAAkDL;YACtD;QACF,EAAE,eAAM;QACN,yDAAyD;QAC3D;IACF;IAEA,OAAO9E,SAASC,IAAI,CAClB;QACEb;QACAkG,WAAW,GAAEhG,uBAAAA,QAAQgG,WAAW,YAAnBhG,uBAAuBF;QACpCmG,WAAW,GAAEjG,uBAAAA,QAAQiG,WAAW,YAAnBjG,uBAAuB;QACpC,mEAAmE;QACnE,uEAAuE;QACvE,6BAA6B;QAC7BkG,qBAAqBlG,QAAQkG,mBAAmB,GAC5C;YACEC,OAAO/E,QAAOpB,qCAAAA,QAAQkG,mBAAmB,CAACC,KAAK,YAAjCnG,qCAAqC;YACnDoG,WAAW,YACTpG,2CAAAA,QAAQkG,mBAAmB,CAACE,WAAW,sBAAvCpG,mDAAAA,yCAAyC4B,MAAM,sBAA/C5B,kDAAAA,sDAAAA,8DAAAA,gDAAqD6B,WAAW,sBAChE;YACFwE,aAAa,GAAErG,6CAAAA,QAAQkG,mBAAmB,CAACG,aAAa,YAAzCrG,6CAA6C;QAC9D,IACA;QACJsG,MAAM,GAAEtG,kBAAAA,QAAQsG,MAAM,YAAdtG,kBAAkB;QAC1BuG,OAAO,GAAEvG,mBAAAA,QAAQuG,OAAO,YAAfvG,mBAAmB;QAC5BwG,UAAU,GAAExG,sBAAAA,QAAQwG,UAAU,YAAlBxG,sBAAsB,EAAE;QACpCyG,WAAW,GAAEzG,uBAAAA,QAAQyG,WAAW,YAAnBzG,uBAAuB;QACpC,gEAAgE;QAChE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,4DAA4D;QAC5DkC,eAAeqB,CAAAA,+BAAAA,YAAarB,aAAa,KAAIlC,QAAQkC,aAAa,IAAI;QACtEM;QACAkE,aAAa,WAAEhE,6BAAAA,UAAWlC,GAAG,CAAC,2BAAWgC;QACzCmE,aAAa,WAAEjE,6BAAAA,UAAWlC,GAAG,CAAC,2BAAW;QACzCoG,YAAY,GAAE5G,wBAAAA,QAAQ4G,YAAY,YAApB5G,wBAAwB;QACtC6G,eAAe,GAAE7G,2BAAAA,QAAQ6G,eAAe,YAAvB7G,2BAA2B;QAC5C8G,iBAAiB,GAAE9G,6BAAAA,QAAQ8G,iBAAiB,YAAzB9G,6BAA6B;QAChD+G,UAAUvF,QAAOxB,oBAAAA,QAAQ+G,QAAQ,YAAhB/G,oBAAoB;QACrCkD,eAAe9B,QAAOpB,0BAAAA,QAAQkD,aAAa,YAArBlD,0BAAyB;QAC/C,iEAAiE;QACjE,oCAAoC;QACpCiD;QACAlB,gBAAgBP,QAAOxB,0BAAAA,QAAQ+B,cAAc,YAAtB/B,0BAA0B;QACjDgH,QAAQ/E,QAAQjC,QAAQiH,QAAQ;QAChCC,cAAc9F,QAAOpB,wBAAAA,QAAQkH,YAAY,YAApBlH,wBAAwB;QAC7CmH,SAASlF,QAAQW;QACjBwE,eAAe,WAAExE,8BAAAA,WAAY3C,QAAQ,oBAAI;QACzCoH,aAAapF,QAAQjC,QAAQsH,SAAS;QACtCC,SAASvH,QAAQwH,UAAU,KAAK;QAChCC,iBAAiBnK;QACjB,sEAAsE;QACtE,oEAAoE;QACpE,uEAAuE;QACvE,wEAAwE;QACxE,+DAA+D;QAC/D6F,eAAe,EAAEA,0BAAAA,kBAAmB;QACpClD,UAAUA,SAASd,GAAG,CACpB,qEAAqE;QACrE,iEAAiE;QACjE,8DAA8D;QAC9D,qEAAqE;QACrE,8DAA8D;QAC9D,+BAA+B;QAC/B,6DAA6D;QAC7D;gBAAC,EAAEkD,YAAY,EAAEC,eAAe,EAAEC,oBAAoB,EAAY,OAAPS;;;;;mBAAa,aACnEA;gBACH,kEAAkE;gBAClE,8DAA8D;gBAC9D,iDAAiD;gBACjDmE,SAASjK,gBACP0F,YACAI,MAAM7B,OAAO;;;QAInB,sEAAsE;QACtE,qEAAqE;QACrEuG,WAAWrC,OAAOsC,WAAW,CAC3BtC,OAAOuC,OAAO,UACXrE,+BAAAA,YAAajB,eAAe,oBAAI,CAAC,GAKjCiD,MAAM,CAAC,CAAC,GAAGvC,MAAM,GAAKA,CAAAA,yBAAAA,MAAO1B,MAAM,MAAKkC,WACxCrE,GAAG,CAAC,CAAC,CAACE,IAAI2D,MAAM;gBAAgBA;mBAAX;gBAAC3D;gBAAI;oBAAEoG,EAAE,GAAEzC,YAAAA,MAAMyC,EAAE,YAARzC,YAAY;gBAAK;aAAE;;QAExD6E,sBAAsBzJ,0BACpBmF,+BAAAA,YAAajB,eAAe,EAC5BkB,oBAAAA,YAAa;QAEf,sEAAsE;QACtE,sEAAsE;QACtE,qEAAqE;QACrE,qEAAqE;QACrE,qDAAqD;QACrDsE,aAAarJ,qBACX8E,+BAAAA,YAAahB,oBAAoB,EACjCiB,oBAAAA,YAAa;QAEfoC;QACAF;QACA,qEAAqE;QACrE,qEAAqE;QACrE,gEAAgE;QAChE,mEAAmE;QACnEqC,oBAAoB;YAClB5G,OAAO,WAAEhB,8BAAAA,WAAYgB,OAAO,oBAAI;YAChC6G,UAAU,YAAE7H,+BAAAA,yBAAAA,WAAY6H,UAAU,sBAAtB7H,iCAAAA,uBAAwByB,MAAM,sBAA9BzB,gCAAAA,oCAAAA,4CAAAA,8BAAoC0B,WAAW,uBAAM;YACjEoG,UAAUtJ;YACVwH,OAAOvH,wBAAwBuB;QACjC;QACAwD;QACAI;QACAgB,iBAAiBxH;IACnB,GACA;QAAEsD,QAAQ;IAAI;AAElB;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GACD,eAAeqH,4BACb9H,UAA+C,EAC/CwC,UAA+C;IAE/C,MAAM3C,WAAW,MAAMG,WACpBC,UAAU,CAAC,kBACXU,OAAO,CAAC,eAAe,QACvBC,KAAK,CAAC,IACNR,GAAG;IACN,uEAAuE;IACvE,yEAAyE;IACzE,qEAAqE;IACrE,MAAM2H,SAAShL,yBACb8C,SAASgB,IAAI,CAAC9B,GAAG,CAAC,CAACmB,MAAS,CAAA;YAC1Ba,SAASb,IAAIjB,EAAE;YACf8C,aAAa7B,IAAIE,GAAG,CAAC;QACvB,CAAA,IACAoC,YACA1E;IAEF,MAAMH,eAAeqC,YAAY;QAC/BgI,qBAAqB,EAAED,iBAAAA,SAAUtJ,WAAWwJ,MAAM;QAClDC,WAAWzJ,WAAWoG,eAAe;IACvC;AACF;AAEA,eAAesD,QAAQC,OAAgB;QAIfC;IAHtB,MAAM,EAAEC,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAEH,SAASI,UAAU,EAAE,GAChD,MAAMpL,qBAAqB+K;IAC7B,MAAMC,UAAUI;IAChB,MAAMC,iBAAgBL,yBAAAA,QAAQK,aAAa,YAArBL,yBAAyB;IAC/C,MAAMM,UAAUD,cAAcE,UAAU,CAAC,aACrCF,cAAcG,KAAK,CAAC,UAAUC,MAAM,IACpC9D;IACJ,IAAI,CAAC2D,SAAS,OAAOrI,SAASC,IAAI,CAAC;QAAEC,OAAO;IAAkB,GAAG;QAAEC,QAAQ;IAAI;IAE/E,IAAI;;YA06BEb;QAz6BJ,MAAMmJ,UAAU,MAAMtL,cAAcoG,GAAG,GAAGmF,IAAI,GAAGC,aAAa,CAACN;QAC/D,IAAI,CAACI,QAAQG,cAAc,IAAI,CAACxL,uBAAuBqL,UAAU;YAC/D,OAAOxL;QACT;QACA,IAAI,CAACwL,OAAO,CAAC,QAAQ,EAAE;YACrB,OAAOzI,SAASC,IAAI,CAAC;gBAAEC,OAAO;YAAa,GAAG;gBAAEC,QAAQ;YAAI;QAC9D;QACA,MAAMhB,YAAYhC,cAAcoG,GAAG,GAAGpE,SAAS;QAE/C,IAAI6I,WAAW,OAAO;gBACIE;YAAxB,MAAMW,WAAWnI,QAAOwH,mBAAAA,KAAK,CAAC,YAAY,YAAlBA,mBAAsB;YAC9C,IAAIW,UAAU;oBACqCX;gBAAjD,OAAOhJ,cAAcC,WAAW0J,UAAUnI,QAAOwH,iBAAAA,KAAK,CAAC,UAAU,YAAhBA,iBAAoB;YACvE;YAEA,iEAAiE;YACjE,kEAAkE;YAClE,qEAAqE;YACrE,qEAAqE;YACrE,iEAAiE;YACjE,oEAAoE;YACpE,0BAA0B;YAC1B,MAAMrI,WAAW,MAAMV,UACpBQ,UAAU,CAAC,uBACXmJ,KAAK,CAAC,QAAQ,MAAM,UACpBxI,KAAK,CAAC,KACNR,GAAG;YACN,oEAAoE;YACpE,kEAAkE;YAClE,iEAAiE;YACjE,+CAA+C;YAC/C,MAAMiJ,OAAO,MAAMC,QAAQC,GAAG,CAC5BpJ,SAASU,IAAI,CACVsE,MAAM,CAAC,CAACjF,MAAQ,CAACA,IAAIE,GAAG,CAAC,cACzBrB,GAAG,CAAC,OAAOmB;oBAEaN,wBAMRA,sBACAA,sBACJA,kBACGA,qBAEEA,uBACGA,yBAOIA;gBApBvB,MAAMA,UAAUM,IAAIG,IAAI;gBACxB,MAAMU,UAAUC,QAAOpB,yBAAAA,QAAQkD,aAAa,YAArBlD,yBAAyB;gBAChD,MAAM4J,SAASzI,UACX,MAAMb,IAAIuJ,GAAG,CAACxJ,UAAU,CAAC,kBAAkBC,GAAG,CAACa,SAASX,GAAG,KAC3D;gBACJ,OAAO;oBACLV,WAAWQ,IAAIjB,EAAE;oBACjB2G,WAAW,GAAEhG,uBAAAA,QAAQgG,WAAW,YAAnBhG,uBAAuBM,IAAIjB,EAAE;oBAC1C4G,WAAW,GAAEjG,uBAAAA,QAAQiG,WAAW,YAAnBjG,uBAAuB;oBACpCuG,OAAO,GAAEvG,mBAAAA,QAAQuG,OAAO,YAAfvG,mBAAmB;oBAC5BwG,UAAU,GAAExG,sBAAAA,QAAQwG,UAAU,YAAlBxG,sBAAsB,EAAE;oBACpCyC,WAAWzC,QAAQyC,SAAS;oBAC5BmE,YAAY,GAAE5G,wBAAAA,QAAQ4G,YAAY,YAApB5G,wBAAwB;oBACtC+G,UAAUvF,QAAOxB,oBAAAA,QAAQ+G,QAAQ,YAAhB/G,oBAAoB;oBACrCmB;oBACA6F,QAAQ/E,QAAQjC,QAAQiH,QAAQ;oBAChCM,SAASvH,QAAQwH,UAAU,KAAK;oBAChCsC,mBAAmB1I,eAAOwI,0BAAAA,OAAQpJ,GAAG,CAAC,iCAAkB;oBACxD4B,eAAeH,QAAQ2H,0BAAAA,OAAQpJ,GAAG,CAAC;oBACnC,yDAAyD;oBACzD0F,mBAAmB,GAAElG,+BAAAA,QAAQkG,mBAAmB,YAA3BlG,+BAA+B;gBACtD;YACF;YAEJ,oEAAoE;YACpE,+DAA+D;YAC/D,MAAM+J,QAAQN,KAAKlE,MAAM,CAAC,CAACyE,MAAQA,IAAIF,iBAAiB,KAAK;YAC7D,mEAAmE;YACnE,yEAAyE;YACzE,sEAAsE;YACtE,sEAAsE;YACtE,sEAAsE;YACtE,uEAAuE;YACvE,wCAAwC;YACxC,MAAMG,uBAAuBR,KAAKlE,MAAM,CACtC,CAACyE;oBAAQA;uBAAAA,EAAAA,2BAAAA,IAAI9D,mBAAmB,qBAAvB8D,yBAAyB7D,KAAK,MAAK;;YAE9C,mEAAmE;YACnE,qEAAqE;YACrE,+DAA+D;YAC/D,gEAAgE;YAChE,qCAAqC;YACrC,MAAM+D,iBAAiB;gBACrBjJ,MAAMV,SAASU,IAAI,CAACsE,MAAM,CAAC,CAACjF;wBACaA;2BAAvC;wBAAC;wBAAU;qBAAW,CAAC6J,QAAQ,CAAC/I,QAAOd,WAAAA,IAAIE,GAAG,CAAC,2BAARF,WAA2B;;YAEtE;YACA,MAAM8J,SAAS,MAAMV,QAAQC,GAAG,CAC9BO,eAAejJ,IAAI,CAAC9B,GAAG,CAAC,OAAOmB;oBAcdN,sBAGSA,wBAKDA;gBArBvB,MAAMA,UAAUM,IAAIG,IAAI;gBACxB,MAAMK,mBAAmB,MAAMR,IAAIuJ,GAAG,CACnCxJ,UAAU,CAAC,kBACXU,OAAO,CAAC,eAAe,QACvBC,KAAK,CAAC,IACNR,GAAG;gBACN,MAAMP,WAAWa,iBAAiBG,IAAI,CAAC9B,GAAG,CAAC,CAACkL;wBAC1BA,iBACTA,kBACaA;2BAHsC;wBAC1DlJ,SAASC,QAAOiJ,kBAAAA,WAAW7J,GAAG,CAAC,sBAAf6J,kBAA6BA,WAAWhL,EAAE;wBAC1DgC,KAAK,GAAEgJ,mBAAAA,WAAW7J,GAAG,CAAC,oBAAf6J,mBAA2B;wBAClClI,aAAaf,QAAOiJ,mBAAAA,WAAW7J,GAAG,CAAC,0BAAf6J,mBAAiC;oBACvD;;gBACA,OAAO;oBACLvK,WAAWQ,IAAIjB,EAAE;oBACjB2G,WAAW,GAAEhG,uBAAAA,QAAQgG,WAAW,YAAnBhG,uBAAuBM,IAAIjB,EAAE;oBAC1CuH,cAAc5G,QAAQ4G,YAAY;oBAClCnE,WAAWzC,QAAQyC,SAAS;oBAC5BS,eAAe9B,QAAOpB,yBAAAA,QAAQkD,aAAa,YAArBlD,yBAAyB;oBAC/C,+DAA+D;oBAC/D,8DAA8D;oBAC9D,qCAAqC;oBACrCgH,QAAQ/E,QAAQjC,QAAQiH,QAAQ;oBAChCC,cAAc9F,QAAOpB,wBAAAA,QAAQkH,YAAY,YAApBlH,wBAAwB;oBAC7CuH,SAASvH,QAAQwH,UAAU,KAAK;oBAChC8C,iBAAiBrK,SAASsF,MAAM,CAC9B,CAACvC,QAAUA,MAAMb,WAAW,KAAK,YACjC+G,MAAM;oBACR,+DAA+D;oBAC/D,yBAAyB;oBACzBqB,eAAetK,SAASsF,MAAM,CAAC,CAACvC,QAAUA,MAAM3B,KAAK,KAAK,SACvD6H,MAAM;oBACTsB,cAAcvK,SAASiJ,MAAM;oBAC7BjJ;gBACF;YACF;YAGF,gEAAgE;YAChE,wDAAwD;YACxD,MAAMwK,eAAe;mBAChB,IAAIvL,IACL;uBAAI6K;uBAAUK;iBAAO,CAClBjL,GAAG,CAAC,CAAC6D;wBAAiBA;2BAAP5B,QAAO4B,mBAAAA,MAAMP,SAAS,YAAfO,mBAAmB;mBACzCuC,MAAM,CAACtD;aAEb;YACD,MAAMyI,aAAqC,CAAC;YAC5C,IAAID,aAAavB,MAAM,EAAE;gBACvB,MAAMjI,OAAO,MAAMpB,UAAU8K,MAAM,IAC9BF,aAAatL,GAAG,CAAC,CAACE,KAAOQ,UAAUQ,UAAU,CAAC,QAAQC,GAAG,CAACjB;gBAE/D,KAAK,MAAMiB,OAAOW,KAAM;wBACsBX;oBAA5C,IAAIA,IAAIsK,MAAM,EAAEF,UAAU,CAACpK,IAAIjB,EAAE,CAAC,GAAG+B,QAAOd,WAAAA,IAAIE,GAAG,CAAC,mBAARF,WAAmBA,IAAIjB,EAAE;gBACvE;YACF;YACA,OAAOqB,SAASC,IAAI,CAClB;gBAAEoJ;gBAAOK;gBAAQM;gBAAYT;YAAqB,GAClD;gBAAEpJ,QAAQ;YAAI;QAElB;QAEA,IAAI6H,WAAW,QAAQ;YACrB,OAAOhI,SAASC,IAAI,CAAC;gBAAEC,OAAO;YAAqB,GAAG;gBAAEC,QAAQ;YAAI;QACtE;QACA,MAAMf,YAAYsB,eAAOuH,wBAAAA,KAAM7I,SAAS,mBAAI;QAC5C,MAAM+K,SAASzJ,gBAAOuH,wBAAAA,KAAMkC,MAAM,oBAAI;QAEtC,wEAAwE;QACxE,qEAAqE;QACrE,sEAAsE;QACtE,0DAA0D;QAC1D,IAAIA,WAAW,UAAUA,WAAW,UAAU;;YAC5C,IAAI,CAAC/K,WAAW;gBACd,OAAOY,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAoB,GAAG;oBAAEC,QAAQ;gBAAI;YACrE;YACA,MAAMiK,aAAa1J,gBAAOuH,wBAAAA,KAAMoC,MAAM,oBAAI,IAAI9B,KAAK,CAAC,GAAG;YACvD,IAAI4B,WAAW,UAAU,CAACC,WAAWE,IAAI,IAAI;gBAC3C,OAAOtK,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAwB,GAAG;oBAAEC,QAAQ;gBAAI;YACzE;YACA,MAAMoK,YAAY7J,gBAAOuH,wBAAAA,KAAMsC,SAAS,oBAAI;YAC5C,MAAMC,SAASD,YACXpL,UACGQ,UAAU,CAAC,uBACXC,GAAG,CAACR,WACJO,UAAU,CAAC,WACXC,GAAG,CAAC2K,aACPpL,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR;YACpD,MAAMqL,iBAAiB,MAAMD,OAAO1K,GAAG;YACvC,IAAI,CAAC2K,eAAeP,MAAM,EAAE;gBAC1B,OAAOlK,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAiB,GAAG;oBAAEC,QAAQ;gBAAI;YAClE;YACA,uEAAuE;YACvE,EAAE;YACF,wEAAwE;YACxE,yEAAyE;YACzE,yEAAyE;YACzE,wDAAwD;YACxD,EAAE;YACF,sEAAsE;YACtE,wEAAwE;YACxE,uEAAuE;YACvE,EAAE;YACF,qEAAqE;YACrE,2EAA2E;YAC3E,0EAA0E;YAC1E,mEAAmE;YACnE,MAAMuK,gBAAgBrO,8BAA8B;gBAClD8N;gBACAjE,cAAcuE,eAAe3K,GAAG,CAAC;gBACjC6K,iBAAiB,CAACJ;YACpB;YACA,MAAMC,OAAOpG,GAAG,CACdmG,YACI;gBAAEjE,QAAQ6D,WAAW;YAAO,IAC5BA,WAAW,SACT;gBACE5D,UAAUpI,WAAWoG,eAAe;gBACpCqG,UAAUnC,QAAQoC,GAAG;gBACrBrE,cAAc4D;eACVM,gBACA;gBAAExE,cAAc5J;YAAyB,IACzC,CAAC,KAEP;gBACEiK,UAAUpI,WAAWwJ,MAAM;gBAC3BiD,UAAUzM,WAAWwJ,MAAM;gBAC3BnB,cAAcrI,WAAWwJ,MAAM;YACjC,GACN;gBAAEnD,OAAO;YAAK;YAGhB,kEAAkE;YAClE,8DAA8D;YAC9D,kEAAkE;YAClE,qEAAqE;YACrE,gEAAgE;YAChE,oEAAoE;YACpE,0DAA0D;YAC1D,MAAMsG,WACJ,CAACP,aACAE,CAAAA,eAAe3K,GAAG,CAAC,oBAAoB,YACtC2K,eAAe3K,GAAG,CAAC,YAAY,QAAO;YAC1C;;;;;;;;;;;;;;OAcC,GACD,MAAMiL,uBACJD,YACC,CAACP,aAAaE,eAAe3K,GAAG,CAAC,oBAAoB;YACxD,IAAIiL,sBAAsB;gBACxB,MAAMC,gBAAgB7L,UAAUQ,UAAU,CAAC,eAAeC,GAAG,CAACR;gBAC9D,MAAM6L,UAAU,AAAC,CAAA,MAAMD,cAAclL,GAAG,EAAC,EAAGC,IAAI;gBAGhD,gEAAgE;gBAChE,sEAAsE;gBACtE,oEAAoE;gBACpE,iEAAiE;gBACjE,6DAA6D;gBAC7D,MAAMmL,OAAOvO,oBAAoBsO,SAAS;oBACxCE,MAAMhB,WAAW,SAAS,aAAa;gBACzC;gBACA,IAAIe,MAAM;oBACR,MAAMF,cAAc5G,GAAG,CACrB,aACK8G,MACCf,WAAW,SAAS;wBAAEE,QAAQD;oBAAW,IAAI,CAAC;wBAClDgB,WAAW3C,QAAQoC,GAAG;wBACtBQ,WAAWlN,WAAWoG,eAAe;uBAGjC4F,WAAW,SAAS,CAAC,IAAI;wBAAEmB,QAAQnN,WAAWwJ,MAAM;oBAAG,IAE7D;wBAAEnD,OAAO;oBAAK;gBAElB,OAAO,IAAIyG,SAAS;oBAClB,MAAMD,cAAcrD,MAAM;gBAC5B;gBACA,kEAAkE;gBAClE,sEAAsE;gBACtE,qEAAqE;gBACrE,oEAAoE;gBACpE,6DAA6D;gBAC7D,EAAE;gBACF,gEAAgE;gBAChE,qEAAqE;gBACrE,yDAAyD;gBACzD,IAAImD,UAAU,MAAMxM,qBAAqBa,WAAWC;gBACpD,kEAAkE;gBAClE,kEAAkE;gBAClE,sEAAsE;gBACtE,sEAAsE;gBACtE,qEAAqE;gBACrE,kEAAkE;gBAClE,oEAAoE;gBACpE,oEAAoE;gBACpE,oEAAoE;gBACpE,8DAA8D;gBAC9D,EAAE;gBACF,oEAAoE;gBACpE,sEAAsE;gBACtE,iEAAiE;gBACjE,oEAAoE;gBACpE,EAAE;gBACF,gEAAgE;gBAChE,mEAAmE;gBACnE,qEAAqE;gBACrE,gEAAgE;gBAChE,IAAI0L,UAAU;oBACZ,MAAMtD,4BACJrI,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR,YAChD8L;gBAEJ;YACF;YAEA,MAAM/L,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;gBAC3CC,UAAU/C,QAAQoC,GAAG;gBACrBV,QAAQ,CAAC,iBAAiB,EAAEA,QAAQ;gBACpCK,QAAQD,YACJ,CAAC,oBAAoB,EAAEnL,UAAU,SAAS,EAAEmL,WAAW,GACvD,CAAC,oBAAoB,EAAEnL,WAAW;eAOlCmL,YAAY;gBAAEkB,YAAYlB;YAAU,IAAI,CAAC;gBAC7CmB,OAAO;oBACLpF,QAAQ6D,WAAW;mBACfC,aAAa;oBAAEC,QAAQD;gBAAW,IAAI,CAAC,GACvCW,uBAAuB;oBAAEtE,SAAS0D,WAAW;gBAAO,IAAI,CAAC,GAIzDO,gBAAgB;oBAAEiB,YAAY;gBAAK,IAAI,CAAC;gBAE9C1G,IAAI9G,WAAWoG,eAAe;;YAGhC,OAAOvE,SAASC,IAAI,CAClB;gBACEiD,IAAI;gBACJoD,QAAQ6D,WAAW;gBACnB1D,SAASsE,wBAAwBZ,WAAW;gBAC5C,iEAAiE;gBACjE,qCAAqC;gBACrCwB,YAAYjB;YACd,GACA;gBAAEvK,QAAQ;YAAI;QAElB;QAEA,wEAAwE;QACxE,mEAAmE;QACnE,IAAIgK,WAAW,aAAa;8BAwBCyB,sBAiBRA;YAxCnB,MAAMnL,UAAUC,gBAAOuH,wBAAAA,KAAMxH,OAAO,oBAAI;YACxC,MAAMoL,SAASnL,gBAAOuH,wBAAAA,KAAM4D,MAAM,oBAAI;YACtC,MAAMC,UAAU7D,CAAAA,wBAAAA,KAAM6D,OAAO,MAAK;YAClC,IAAI,CAAC1M,aAAa,CAACqB,WAAW,CAAClC,qBAAqBwN,GAAG,CAACF,SAAS;gBAC/D,OAAO7L,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAyB,GAAG;oBAAEC,QAAQ;gBAAI;YAC1E;YACA,MAAM6L,aAAa7M,UAChBQ,UAAU,CAAC,uBACXC,GAAG,CAACR,WACJO,UAAU,CAAC,kBACXC,GAAG,CAACa;YACP,MAAMmL,kBAAkB,MAAMI,WAAWlM,GAAG;YAC5C,IAAI,CAAC8L,gBAAgB1B,MAAM,EAAE;gBAC3B,OAAOlK,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAkB,GAAG;oBAAEC,QAAQ;gBAAI;YACnE;YACA,MAAM6L,WAAW5H,GAAG,CAClB;gBACExC,iBAAiB;oBACf,CAACiK,OAAO,EAAEC,UACN;wBACE/G,IAAI0D,QAAQoC,GAAG;wBACf5F,IAAI9G,WAAWoG,eAAe;wBAC9B,kDAAkD;wBAClD3D,QAAQF,QAAOkL,uBAAAA,gBAAgB9L,GAAG,CAAC,qBAApB8L,uBAAiC;oBAClD,IACAzN,WAAWwJ,MAAM;gBACvB;YACF,GACA;gBAAEnD,OAAO;YAAK;YAEhB,iEAAiE;YACjE,iEAAiE;YACjE,wCAAwC;YACxC,MAAMrF,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;gBAC3CC,UAAU/C,QAAQoC,GAAG;gBACrBV,QAAQ,CAAC,yBAAyB,EAAE2B,UAAU,UAAU,WAAW;gBACnEtB,QAAQ,CAAC,oBAAoB,EAAEpL,UAAU,gBAAgB,EAAEqB,SAAS;gBACpEiL,OAAO;oBACLG;oBACAC;oBACAlL,QAAQF,QAAOkL,wBAAAA,gBAAgB9L,GAAG,CAAC,qBAApB8L,wBAAiC;gBAClD;gBACA3G,IAAI9G,WAAWoG,eAAe;YAChC;YACA,OAAOvE,SAASC,IAAI,CAAC;gBAAEiD,IAAI;gBAAM2I;gBAAQC;YAAQ,GAAG;gBAAE3L,QAAQ;YAAI;QACpE;QAEA,uEAAuE;QACvE,iEAAiE;QACjE,uEAAuE;QACvE,6CAA6C;QAC7C,IAAIgK,WAAW,qBAAqBA,WAAW,kBAAkB;uBAkCzCyB,sCA0FXtM,wBAO+BA,uBA4BxBA,gCA+BUsM;YA7L5B,MAAMnL,UAAUC,gBAAOuH,wBAAAA,KAAMxH,OAAO,oBAAI;YACxC,MAAMf,aAAaP,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR;YACnE,MAAM4M,aAAatM,WAAWC,UAAU,CAAC,kBAAkBC,GAAG,CAACa;YAC/D,MAAMmL,kBAAkB,MAAMI,WAAWlM,GAAG;YAC5C,IAAI,CAAC8L,gBAAgB1B,MAAM,EAAE;gBAC3B,OAAOlK,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAkB,GAAG;oBAAEC,QAAQ;gBAAI;YACnE;YACA,qEAAqE;YACrE,sEAAsE;YACtE,8DAA8D;YAC9D,uEAAuE;YACvE,EAAE;YACF,qEAAqE;YACrE,kEAAkE;YAClE,4DAA4D;YAC5D,uEAAuE;YACvE,uEAAuE;YACvE,qEAAqE;YACrE,qEAAqE;YACrE,oEAAoE;YACpE,mEAAmE;YACnE,+DAA+D;YAC/D,EAAE;YACF,iEAAiE;YACjE,uEAAuE;YACvE,gEAAgE;YAChE,qEAAqE;YACrE,qEAAqE;YACrE,MAAM8L,kBAAkB,MAAMvM,WAAWI,GAAG;YAC5C,IAAI,CAACmM,gBAAgB/B,MAAM,EAAE;gBAC3B,OAAOlK,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAkB,GAAG;oBAAEC,QAAQ;gBAAI;YACnE;YACA,MAAMb,UAAU2M,gBAAgBlM,IAAI;YACpC,MAAMa,SAASF,QAAOkL,wBAAAA,gBAAgB9L,GAAG,CAAC,qBAApB8L,wBAAiC;YACvD,MAAMM,YAAY/B,WAAW;YAC7B,IAAI+B,WAAW;gBACb,MAAMC,cAAczO,0BAClBkO,gBAAgB9L,GAAG,CAAC,oBACpBc;gBAEF,IAAIuL,YAAY3D,MAAM,EAAE;oBACtB,OAAOxI,SAASC,IAAI,CAClB;wBACEC,OAAO,CAAC,8BAA8B,EAAEiM,YAAY3D,MAAM,CAAC,6CAA6C,CAAC;wBACzG2D;oBACF,GACA;wBAAEhM,QAAQ;oBAAI;gBAElB;YACF;YACA,MAAMkK,SAAS3J,gBAAOuH,wBAAAA,KAAMoC,MAAM,oBAAI,IAAI9B,KAAK,CAAC,GAAG;YACnD,wEAAwE;YACxE,uEAAuE;YACvE,oEAAoE;YACpE,MAAM6D,WAAW1L,iBAAOuH,wBAAAA,KAAMmE,QAAQ,qBAAI;YAC1C,IAAI,CAACF,WAAW;gBACd,MAAMG,UAAUvO,oBAAoBsO,UAAU/B;gBAC9C,IAAIgC,SAAS,OAAOrM,SAASC,IAAI,CAAC;oBAAEC,OAAOmM;gBAAQ,GAAG;oBAAElM,QAAQ;gBAAI;YACtE;YACA,MAAM6L,WAAW5H,GAAG,CAClB;gBACE3C,aAAayK,YAAY,aAAa;gBACtCI,YAAY7D,QAAQoC,GAAG;gBACvB0B,YAAYpO,WAAWoG,eAAe;gBACtC,gEAAgE;gBAChE,0DAA0D;gBAC1DiI,gBAAgB5L;gBAChBc,eAAevD,WAAWwJ,MAAM;eAC5BuE,YACA;gBACE,wDAAwD;gBACxD,oDAAoD;gBACpD,qCAAqC;gBACrCO,uBAAuBtO,WAAWwJ,MAAM;gBACxC+E,yBAAyBvO,WAAWwJ,MAAM;YAC5C,IACA;gBACE8E,uBAAuBpC;gBACvBqC,yBAAyBN;gBACzB,yDAAyD;gBACzD,EAAE;gBACF,6DAA6D;gBAC7D,0DAA0D;gBAC1D,8DAA8D;gBAC9D,uDAAuD;gBACvD,6DAA6D;gBAC7D,0DAA0D;gBAC1D,6DAA6D;gBAC7D,yDAAyD;gBACzD,UAAU;gBACV,EAAE;gBACF,yDAAyD;gBACzD,2DAA2D;gBAC3D,4DAA4D;gBAC5D,0DAA0D;gBAC1D,0DAA0D;gBAC1D,uDAAuD;gBACvD,2DAA2D;gBAC3D,oDAAoD;gBACpDzL,OAAOxC,WAAWwJ,MAAM;gBACxBgF,WAAWxO,WAAWwJ,MAAM;gBAC5BiF,gBAAgBzO,WAAWwJ,MAAM;gBACjCkF,gBAAgB1O,WAAWwJ,MAAM;YACnC,IAEN;gBAAEnD,OAAO;YAAK;YAGhB,oEAAoE;YACpE,gEAAgE;YAChE,qEAAqE;YACrE,EAAE;YACF,uEAAuE;YACvE,uEAAuE;YACvE,sEAAsE;YACtE,qEAAqE;YACrE,wEAAwE;YACxE,sCAAsC;YAEtC,uEAAuE;YACvE,mEAAmE;YACnE,kEAAkE;YAClE,iEAAiE;YACjE,IAAI9D,QAAOpB,yBAAAA,QAAQkD,aAAa,YAArBlD,yBAAyB,QAAQmB,SAAS;gBACnD,MAAMpD,eAAeqC,YAAY;oBAC/BoN,0BAA0BZ,YAAY,aAAa;gBACrD;YACF;YACA,IACEA,aACA,CAAC;gBAAC;gBAAU;aAAW,CAACzC,QAAQ,CAAC/I,QAAOpB,wBAAAA,QAAQ4G,YAAY,YAApB5G,wBAAwB,MAChE;gBACA,MAAMjC,eAAeqC,YAAY;oBAC/BwG,cAAc;oBACd0B,WAAWzJ,WAAWoG,eAAe;gBACvC;YACF;YAEA,uEAAuE;YACvE,gEAAgE;YAChE,oEAAoE;YACpE,uEAAuE;YACvE,gDAAgD;YAChD,EAAE;YACF,wEAAwE;YACxE,yEAAyE;YACzE,4BAA4B;YAC5B,IAAI2H,WAAW;oBAIV1O;gBAHH,MAAMuP,WAAWzN,QAAQoI,qBAAqB;gBAC9C,IACEqF,YAAY,QACZ,EAACvP,2BAAAA,wBAAwBkD,OAAOqM,WAAWtM,oBAA1CjD,2BAAsD,KAAK,GAC5D;oBACA,MAAMH,eAAeqC,YAAY;wBAC/BgI,uBAAuBjH;wBACvBmH,WAAWzJ,WAAWoG,eAAe;oBACvC;gBACF;YACF,OAAO,IAAI7D,QAAOpB,iCAAAA,QAAQoI,qBAAqB,YAA7BpI,iCAAiC,QAAQmB,SAAS;gBAClE,oEAAoE;gBACpE,kEAAkE;gBAClE,mEAAmE;gBACnE,6CAA6C;gBAC7C,MAAMyB,aAAa,AACjB,CAAA,MAAM/C,UAAUQ,UAAU,CAAC,eAAeC,GAAG,CAACR,WAAWU,GAAG,EAAC,EAC7DC,IAAI;gBACN,MAAMyH,4BAA4B9H,YAAYwC;YAChD;YAEA,MAAM/C,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;gBAC3CC,UAAU/C,QAAQoC,GAAG;gBACrBV,QAAQ,CAAC,uBAAuB,EAAE+B,YAAY,YAAY,UAAU;gBACpE1B,QAAQ,CAAC,oBAAoB,EAAEpL,UAAU,gBAAgB,EAAEqB,SAAS;gBACpEiL,OAAO;oBACL9K;mBACIyJ,SAAS;oBAAEA;gBAAO,IAAI,CAAC,GAIvB+B,WAAW;oBAAEA;gBAAS,IAAI,CAAC;gBAEjCnH,IAAI9G,WAAWoG,eAAe;YAChC;YAEA,sEAAsE;YACtE,2DAA2D;YAC3D,kEAAkE;YAClE,kEAAkE;YAClE,iDAAiD;YACjD,MAAMyI,eAAelM,QAAO8K,wBAAAA,gBAAgB9L,GAAG,CAAC,6BAApB8L,wBAAyC;YACrE,MAAMqB,WAAW,CAACf,aAAac,eAAe;YAE9C,IAAI1N,QAAQyC,SAAS,EAAE;gBACrB,MAAM3D,gBAAgBsC,OAAOpB,QAAQyC,SAAS,GAAG;oBAC/CoJ,MAAM;oBACN+B,OAAOhB,YACH,CAAC,CAAC,EAAE5M,QAAQgG,WAAW,CAAC,GAAG,EAAE7E,QAAQ,SAAS,CAAC,GAC/C,CAAC,CAAC,EAAEnB,QAAQgG,WAAW,CAAC,GAAG,EAAE7E,QAAQ,iBAAiB,CAAC;oBAC3DwH,MAAMiE,YACF,gDACAe,WACE,GAAG5C,OAAO,uCAAuC,CAAC,GAClD,GAAG2C,aAAa,KAAK,EAAEA,iBAAiB,IAAI,KAAK,IAAI,EAAE,CAAC,GACxD,8DACA3C;oBACN8C,OAAOzM,OAAOpB,QAAQyC,SAAS;oBAC/BqL,MAAM;gBACR,GAAG3I,KAAK,CAAC,IAAMC;gBACf,MAAMrG,eACJqC,OAAOpB,QAAQyC,SAAS,GACxBmK,YACI,GAAG5M,QAAQgG,WAAW,CAAC,EAAE,EAAE7E,QAAQ,cAAc,CAAC,GAClD,GAAGnB,QAAQgG,WAAW,CAAC,EAAE,EAAE7E,QAAQ,iBAAiB,CAAC,EACzDyL,YACI,CAAC,oBAAoB,EAAEzL,QAAQ,8BAA8B,CAAC,GAC9D,iEACA,6DACA,CAAC,oBAAoB,EAAEA,QAAQ,sBAAsB,CAAC,GACtD,CAAC,QAAQ,EAAE4J,OAAO,0CAA0C,CAAC,GAC7D,mEACA,sCACC4C,CAAAA,WACG,CAAC,WAAW,EAAExM,QAAQ,uBAAuB,CAAC,GAC9C,GAAGuM,aAAa,KAAK,EAAEA,iBAAiB,IAAI,KAAK,IAAI,EAAE,CAAC,GACxD,2DACA,6DACA,aACA,EAAC;YAEb;YAEA,OAAOhN,SAASC,IAAI,CAClB;gBACEiD,IAAI;gBACJzC;gBACAgB,aAAayK,YAAY,aAAa;gBACtC,iEAAiE;gBACjE,2DAA2D;gBAC3Dc;gBACAC;YACF,GACA;gBAAE9M,QAAQ;YAAI;QAElB;QAEA,yEAAyE;QACzE,sEAAsE;QACtE,wEAAwE;QACxE,kEAAkE;QAClE,wEAAwE;QACxE,yDAAyD;QACzD,EAAE;QACF,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,0EAA0E;QAC1E,2EAA2E;QAC3E,uEAAuE;QACvE,4EAA4E;QAC5E,8BAA8B;QAC9B,EAAE;QACF,2EAA2E;QAC3E,sEAAsE;QACtE,yDAAyD;QACzD,IAAIgK,WAAW,oBAAoBA,WAAW,oBAAoB;wBAShD,OAiDQ7K;YAzDxB,MAAMmB,UAAUC,iBAAOuH,wBAAAA,KAAMxH,OAAO,qBAAI;YACxC,IAAI,CAACrB,aAAa,CAACqB,SAAS;gBAC1B,OAAOT,SAASC,IAAI,CAClB;oBAAEC,OAAO;gBAA+B,GACxC;oBAAEC,QAAQ;gBAAI;YAElB;YACA,MAAMT,aAAaP,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR;YACnE,MAAME,WAAU,QAAA,AAAC,CAAA,MAAMI,WAAWI,GAAG,EAAC,EAAGC,IAAI,cAA7B,QAAmC,CAAC;YACpD,MAAMiL,gBAAgB7L,UAAUQ,UAAU,CAAC,eAAeC,GAAG,CAACR;YAC9D,MAAM6L,UAAU,AAAC,CAAA,MAAMD,cAAclL,GAAG,EAAC,EAAGC,IAAI;YAGhD,MAAMsN,WAAWlD,WAAW;YAC5B,MAAMe,OAAOvO,oBAAoBsO,SAAS;gBACxCE,MAAMkC,WAAW,mBAAmB;gBACpC5M;YACF;YACA,IAAIyK,MAAM;oBAIWjD;gBAHnB,MAAM+C,cAAc5G,GAAG,CACrB,aACK8G;oBACHb,QAAQ3J,QAAOuH,mBAAAA,wBAAAA,KAAMoC,MAAM,qBAAIY,2BAAAA,QAASZ,MAAM,YAA/BpC,SAAmC,IAAIM,KAAK,CAAC,GAAG;oBAC/D6C,WAAW3C,QAAQoC,GAAG;oBACtBQ,WAAWlN,WAAWoG,eAAe;oBAEvC;oBAAEC,OAAO;gBAAK;YAElB,OAAO;gBACL,MAAMwG,cAAcrD,MAAM;YAC5B;YACA,kEAAkE;YAClE,sEAAsE;YACtE,mBAAmB;YACnB,MAAMrJ,qBAAqBa,WAAWC;YAEtC,0EAA0E;YAC1E,0CAA0C;YAC1C,EAAE;YACF,6EAA6E;YAC7E,0EAA0E;YAC1E,2EAA2E;YAC3E,4EAA4E;YAC5E,4EAA4E;YAC5E,0EAA0E;YAC1E,uEAAuE;YACvE,2BAA2B;YAC3B,EAAE;YACF,yEAAyE;YACzE,yEAAyE;YACzE,4EAA4E;YAC5E,4BAA4B;YAC5B,EAAE;YACF,0EAA0E;YAC1E,yEAAyE;YACzE,MAAMkO,WAAWlR,iCAAiC;gBAChDmR,gBAAgB9M;gBAChB+B,eAAe9B,QAAOpB,0BAAAA,OAAO,CAAC,gBAAgB,YAAxBA,0BAA4B;YACpD;YACA,IAAIgO,UAAU;oBAYG1B;gBAXf,MAAMA,kBAAkB,MAAMlM,WAC3BC,UAAU,CAAC,kBACXC,GAAG,CAACa,SACJX,GAAG;gBACN,MAAMJ,WAAW0E,GAAG,CAClB;oBACE0I,0BAA0BO,WACtBlR,+BAEA,gEAAgE;oBAChE,+CAA+C;oBAC/CuE,QAAOkL,wBAAAA,gBAAgB9L,GAAG,CAAC,0BAApB8L,wBAAsC;gBACnD,GACA;oBAAEpH,OAAO;gBAAK;YAElB;YAEA,qEAAqE;YACrE,wEAAwE;YACxE,sEAAsE;YACtE,4DAA4D;YAC5D,MAAMgD,4BAA4B9H,YAAYwL;YAE9C,MAAM/L,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;gBAC3CC,UAAU/C,QAAQoC,GAAG;gBACrBV,QAAQ,CAAC,mBAAmB,EAAEkD,WAAW,WAAW,WAAW;gBAC/D7C,QAAQ,CAAC,oBAAoB,EAAEpL,UAAU,gBAAgB,EAAEqB,SAAS;gBACpEiL,OAAO;oBACLnM,QAAQ,YAAE2L,wBAAAA,KAAM3L,QAAQ,qBAAI;mBACxB+N,WAAW;oBAAEE,iCAAiC;gBAAK,IAAI,CAAC;gBAE9DvI,IAAI9G,WAAWoG,eAAe;YAChC;YAEA,IAAIjF,QAAQyC,SAAS,EAAE;gBACrB,MAAM3D,gBAAgBsC,OAAOpB,QAAQyC,SAAS,GAAG;oBAC/CoJ,MAAM;oBACN+B,OAAOG,WACH,CAAC,CAAC,EAAE/N,QAAQgG,WAAW,CAAC,GAAG,EAAE7E,QAAQ,YAAY,CAAC,GAClD,CAAC,CAAC,EAAEnB,QAAQgG,WAAW,CAAC,GAAG,EAAE7E,QAAQ,yBAAyB,CAAC;oBACnEwH,MAAMoF,WACF,kEACA,0CACA;oBACJF,OAAOzM,OAAOpB,QAAQyC,SAAS;oBAC/BqL,MAAM;gBACR,GAAG3I,KAAK,CAAC,IAAMC;YACjB;YAEA,OAAO1E,SAASC,IAAI,CAClB;gBAAEiD,IAAI;gBAAMzC;gBAASgG,SAAS4G;YAAS,GACvC;gBAAElN,QAAQ;YAAI;QAElB;QAEA,0EAA0E;QAC1E,uEAAuE;QACvE,qEAAqE;QACrE,sEAAsE;QACtE,eAAe;QACf,IAAIgK,WAAW,wBAAwB;wBAqEP7K;gBAhD1BA;YApBJ,MAAMqG,gBAAgBjF,iBAAOuH,wBAAAA,KAAMoC,MAAM,qBAAI,IAAIC,IAAI,GAAG/B,KAAK,CAAC,GAAG;YACjE,IAAI,CAACnJ,WAAW;gBACd,OAAOY,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAiB,GAAG;oBAAEC,QAAQ;gBAAI;YAClE;YACA,uEAAuE;YACvE,uEAAuE;YACvE,4DAA4D;YAC5D,IAAI,CAACwF,eAAe;gBAClB,OAAO3F,SAASC,IAAI,CAClB;oBAAEC,OAAO;gBAAkD,GAC3D;oBAAEC,QAAQ;gBAAI;YAElB;YACA,MAAMT,aAAaP,UAChBQ,UAAU,CAAC,uBACXC,GAAG,CAACR;YACP,MAAME,UAAU,AAAC,CAAA,MAAMI,WAAWI,GAAG,EAAC,EAAGC,IAAI;YAC7C,IAAI,CAACT,SAAS;gBACZ,OAAOU,SAASC,IAAI,CAAC;oBAAEC,OAAO;gBAAkB,GAAG;oBAAEC,QAAQ;gBAAI;YACnE;YACA,IAAIb,EAAAA,gCAAAA,QAAQkG,mBAAmB,qBAA3BlG,8BAA6BmG,KAAK,MAAK,WAAW;gBACpD,OAAOzF,SAASC,IAAI,CAClB;oBAAEC,OAAO;gBAAqC,GAC9C;oBAAEC,QAAQ;gBAAI;YAElB;YACA,MAAMT,WAAW0E,GAAG,CAClB;gBACEoB,qBAAqB,aAChBlG,QAAQkG,mBAAmB;oBAC9BC,OAAO;oBACPgI,WAAWtP,WAAWoG,eAAe;oBACrCmJ,WAAWjF,QAAQoC,GAAG;oBACtBlF;;YAEJ,GACA;gBAAEnB,OAAO;YAAK;YAEhB;;;;;;;;;;;;;;OAcC,GACD,MAAMrF,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;gBAC3CC,UAAU/C,QAAQoC,GAAG;gBACrB8C,YAAYlF,QAAQpD,KAAK,GAAG3E,OAAO+H,QAAQpD,KAAK,IAAI;gBACpD8E,QAAQ;gBACRyD,OAAO;gBACPpD,QAAQ,CAAC,oBAAoB,EAAEpL,WAAW;gBAC1CyO,QAAQ;oBAAEC,mBAAmB;gBAAU;gBACvCpC,OAAO;oBACLoC,mBAAmB;oBACnBC,cAAc/P;gBAChB;gBACAqM,QAAQ1E;gBACRV,IAAI9G,WAAWoG,eAAe;YAChC;YAEA,MAAMyJ,iBAAiBtN,QAAOpB,qBAAAA,QAAQyC,SAAS,YAAjBzC,qBAAqB;YACnD,IAAI0O,gBAAgB;gBAClB,MAAM5P,gBAAgB4P,gBAAgB;oBACpC7C,MAAM;oBACN+B,OAAO,CAAC,2BAA2B,EAAE5N,QAAQgG,WAAW,CAAC,CAAC,CAAC;oBAC3D,oEAAoE;oBACpE,iEAAiE;oBACjE2C,MACE,GAAGtC,cAAc,gDAAgD,CAAC,GAClE,CAAC,sCAAsC,CAAC,GACxC,GAAG3H,mCAAmC,MAAM,CAAC;oBAC/CmP,OAAOa;oBACPZ,MAAM;gBACR,GAAG3I,KAAK,CAAC,IAAMC;YACjB;YACA,OAAO1E,SAASC,IAAI,CAAC;gBAAEiD,IAAI;gBAAMuC,OAAO;YAAW,GAAG;gBAAEtF,QAAQ;YAAI;QACtE;QAEA,MAAM8N,aAAarP,OAAO,CAACuL,OAAO;QAClC,IAAI,CAAC/K,aAAa,CAAC6O,YAAY;YAC7B,OAAOjO,SAASC,IAAI,CAAC;gBAAEC,OAAO;YAAiB,GAAG;gBAAEC,QAAQ;YAAI;QAClE;QACA,MAAMkK,SAAS3J,gBAAOuH,wBAAAA,KAAMoC,MAAM,oBAAI,IAAI9B,KAAK,CAAC,GAAG;QACnD,MAAM6D,WAAW1L,gBAAOuH,wBAAAA,KAAMmE,QAAQ,oBAAI;QAC1C,IAAIjC,WAAW,UAAU;YACvB,MAAMkC,UAAUvO,oBAAoBsO,UAAU/B;YAC9C,IAAIgC,SAAS,OAAOrM,SAASC,IAAI,CAAC;gBAAEC,OAAOmM;YAAQ,GAAG;gBAAElM,QAAQ;YAAI;QACtE;QAEA,MAAMT,aAAaP,UAAUQ,UAAU,CAAC,uBAAuBC,GAAG,CAACR;QACnE,MAAME,UAAU,AAAC,CAAA,MAAMI,WAAWI,GAAG,EAAC,EAAGC,IAAI;QAC7C,IAAI,CAACT,SAAS,OAAOU,SAASC,IAAI,CAAC;YAAEC,OAAO;QAAkB,GAAG;YAAEC,QAAQ;QAAI;QAE/E,mEAAmE;QACnE,uBAAuB;QACvB,EAAE;QACF,qEAAqE;QACrE,uEAAuE;QACvE,sEAAsE;QACtE,sEAAsE;QACtE,4DAA4D;QAC5D,EAAE;QACF,uEAAuE;QACvE,mEAAmE;QACnE,oDAAoD;QACpD,IAAIgK,WAAW,YAAYA,WAAW,QAAQ;gBACrB7K,yBAOdsM;YAPT,MAAMnL,UAAUC,QAAOpB,0BAAAA,QAAQkD,aAAa,YAArBlD,0BAAyB;YAChD,MAAMsM,kBAAkB,MAAMlM,WAC3BC,UAAU,CAAC,kBACXC,GAAG,CAACa,SACJX,GAAG;YACN,MAAMqM,cAAczO,0BAClBkO,gBAAgB9L,GAAG,CAAC,oBACpBY,QAAOkL,wBAAAA,gBAAgB9L,GAAG,CAAC,qBAApB8L,wBAAiC;YAE1C,IAAIO,YAAY3D,MAAM,EAAE;gBACtB,OAAOxI,SAASC,IAAI,CAClB;oBACEC,OAAO,CAAC,8BAA8B,EAAEiM,YAAY3D,MAAM,CAAC,6BAA6B,CAAC;oBACzF2D;gBACF,GACA;oBAAEhM,QAAQ;gBAAI;YAElB;QACF;QAEA,MAAMT,WAAW0E,GAAG,CAClB;YACE8B,cAAc+H;YACd3B,YAAY7D,QAAQoC,GAAG;YACvB0B,YAAYpO,WAAWoG,eAAe;WASlC4F,WAAW,YACf7K,EAAAA,+BAAAA,QAAQkG,mBAAmB,qBAA3BlG,6BAA6BmG,KAAK,MAAK,YACnC;YACED,qBAAqB,aAChBlG,QAAQkG,mBAAmB;gBAC9BC,OAAO;gBACPgI,WAAWtP,WAAWoG,eAAe;gBACrCmJ,WAAWjF,QAAQoC,GAAG;;QAE1B,IACA,CAAC,GACDV,WAAW,WACX;YAAEhE,iBAAiBkE;YAAQjE,mBAAmBgG;QAAS,IACvD;YACEjG,iBAAiBhI,WAAWwJ,MAAM;YAClCvB,mBAAmBjI,WAAWwJ,MAAM;QACtC,IAEN;YAAEnD,OAAO;QAAK;QAGhB,kEAAkE;QAClE,IACElF,QAAQyC,SAAS,IACjB;YAAC;YAAU;YAAQ;YAAU;SAAS,CAAC0H,QAAQ,CAACU,SAChD;gBAI8B7K;YAH9B,mEAAmE;YACnE,oEAAoE;YACpE,wEAAwE;YACxE,MAAM0O,iBAAiBtN,QAAOpB,sBAAAA,QAAQyC,SAAS,YAAjBzC,sBAAqB;YACnD,MAAM2G,gBAAgB+H,iBACjB,AACC,CAAA,MAAM7O,UAAUQ,UAAU,CAAC,QAAQC,GAAG,CAACoO,gBAAgBlO,GAAG,EAAC,EAC3DA,GAAG,CAAC,UACN4E;YACJ,IAAIsJ,gBAAgB;oBAgBRpQ,0BACAA;gBAhBV,MAAMQ,gBAAgB4P,gBAAgB;oBACpC7C,MAAM;oBACN+B,OACE/C,WAAW,WACP,CAAC,CAAC,EAAE7K,QAAQgG,WAAW,CAAC,cAAc,CAAC,GACvC6E,WAAW,WACT,CAAC,CAAC,EAAE7K,QAAQgG,WAAW,CAAC,mBAAmB,CAAC,GAC5C,CAAC,CAAC,EAAEhG,QAAQgG,WAAW,CAAC,SAAS,EAAE2I,YAAY;oBACvDhG,MACEkC,WAAW,WAEP,8DAA8D;oBAC9D,4DAA4D;oBAC5D,iCAAiC;oBACjC;yBACEvM,2BAAAA,wBAAwBwO,8BAAxBxO,yBAAmCsQ,KAAK;yBACxCtQ,4BAAAA,wBAAwBwO,8BAAxBxO,0BAAmCuQ,QAAQ;wBAC3C9D;qBACD,CACExF,MAAM,CAACtD,SACP6M,IAAI,CAAC,UACRjE,WAAW,WACTE,UACA,4DACE,kDACF;oBACR8C,OAAOa;oBACPZ,MAAMnH,gBACF1I,WAAWE,MAAM4Q,eAAe,EAAE;wBAChCC,SAASrI;oBACX,KACA;gBACN,GAAGxB,KAAK,CAAC,IAAMC;gBACf,MAAMrG,eACJ2P,gBACA7D,WAAW,WACP,GAAG7K,QAAQgG,WAAW,CAAC,gBAAgB,EAAEzH,kBACvCuO,UACA/B,SACC,GACHF,WAAW,WACT,GAAG7K,QAAQgG,WAAW,CAAC,iCAAiC,CAAC,GACzD,GAAGhG,QAAQgG,WAAW,CAAC,QAAQ,EAAE2I,YAAY,EACnD9D,WAAW,YAAYA,WAAW,WAC9BE,UACA,4DACE,kDACF;YAER;QACF;QAEA,MAAMlL,UAAUQ,UAAU,CAAC,cAAc4L,GAAG,CAAC;YAC3CC,UAAU/C,QAAQoC,GAAG;YACrBV,QAAQ,CAAC,eAAe,EAAEA,QAAQ;YAClCK,QAAQ,CAAC,oBAAoB,EAAEpL,WAAW;YAC1CsM,OAAO;gBAAExF,cAAc+H;eAAgB5D,SAAS;gBAAEA;YAAO,IAAI,CAAC;YAC9DpF,IAAI9G,WAAWoG,eAAe;QAChC;QAEA,OAAOvE,SAASC,IAAI,CAAC;YAAEiD,IAAI;YAAMgD,cAAc+H;QAAW,GAAG;YAAE9N,QAAQ;QAAI;IAC7E,EAAE,OAAOD,OAAO;QACd,2DAA2D;QAC3D,uEAAuE;QACvE,MAAMqO,kBAAkBjR,uBAAuB4C;QAC/C,IAAIqO,iBAAiB,OAAOA;QAC5BC,QAAQtO,KAAK,CAACA;QACd,OAAOF,SAASC,IAAI,CAAC;YAAEC,OAAO;QAAuB,GAAG;YAAEC,QAAQ;QAAI;IACxE;AACF;AAEA,SAAS0H,WAAW4G,uBAAuB,GAAE"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/server/admin-reviews.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n REVOKED_VERSION_REVIEW_STATE,\n revocationWithdrawsReviewedClaim,\n shouldStripVerifiedOnTakedown,\n VERIFIED_STRIPPED_STATUS,\n} from '../model/plugin-review-status'\nimport {\n checkPluginBundle,\n isPluginRevoked,\n newestInstallableVersion,\n isStoredVerdictCurrent,\n nextRevocationState,\n PLUGIN_HOST_ABI_VERSION,\n PLUGIN_VERIFIER_VERSION,\n pluginArtifactPath,\n pluginRequestFromWeb,\n readPluginContributions,\n type PluginRevocation,\n type StoredBundleVerdict,\n} from '@aglyn/aglyn/server'\nimport {\n emailUnverifiedResponse,\n findUserByUidAcrossPools,\n firebaseAdmin,\n isImpersonationSession,\n updateExisting,\n} from '@aglyn/tenant-data-admin'\nimport { invalidIdTokenResponse } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport {\n buildRoute,\n compareArtifactVersions,\n Route,\n} from '@aglyn/aglyn/server'\nimport {\n outstandingChecklistItems,\n PLUGIN_REVIEW_CHECKLIST,\n} from '../model/plugin-review-checklist'\nimport {\n pluginRejectionCategory,\n rejectionHeadline,\n rejectionInputError,\n} from '../model/plugin-rejection-categories'\nimport { attestationsForBytes } from '@aglyn/aglyn/app-utils/publisher-attestation'\nimport { VERIFICATION_DECLINE_COOLDOWN_DAYS } from '@aglyn/aglyn/app-utils/marketplace-verification'\nimport {\n PUBLISHER_AGREEMENT_VERSION,\n publisherAgreementState,\n} from '@aglyn/aglyn/app-utils/publisher-agreement'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport { notifyOrgAdmins } from '@aglyn/tenant-data-admin'\n/*\n * The publisher fan-out lives beside the usage-alert one in `_lib` rather\n * than here. Both are multi-recipient platform sends that have to read the\n * platform suppression list before addressing anybody, and that list has to\n * be reachable by a spec that does not drag the admin SDK in behind a route.\n */\nimport { emailPublisher } from './publisher-review-email'\nimport { dropCachesForListing } from './revoke-cache-drop'\n\n/**\n * Marketplace review queue (AGL-432) — Strapi Market's two-phase review\n * as staff tooling. GET returns plugin listings awaiting review\n * (submitted/in_review) with the static-verifier verdict re-run against\n * the stored artifact (the same AGL-426 checks the publish API enforced —\n * re-run here so a reviewer sees them without trusting the publish-time\n * result). POST moves a listing through the lifecycle:\n *\n * start-review → in_review list → listed (publicly browsable)\n * verify → verified (✅ badge) reject → rejected (+ reason,\n * notification to the publisher)\n *\n * Realm trust stays a SEPARATE, super-staff grant (`admin-trust.ts`) —\n * listing/verifying here never signs anything. Every action lands in\n * adminAudit.\n */\n/** Every id the checklist route will accept (AGL-963). */\nconst REQUIRED_OR_OPTIONAL = new Set(\n PLUGIN_REVIEW_CHECKLIST.map((item) => item.id),\n)\n\nconst ACTIONS: Record<string, string> = {\n 'start-review': 'in_review',\n list: 'listed',\n verify: 'verified',\n reject: 'rejected',\n // Moves BACK down the ladder (AGL-965). Review used to be a one-way\n // ratchet: the only retreats were `reject`, which reads as a verdict on\n // the whole listing and notifies the publisher as such, and takedown,\n // which is the kill switch and stops the plugin in every workspace that\n // already installed it. Neither expresses \"pull it from the marketplace\n // while we look again, without breaking the sites already using it\".\n delist: 'in_review',\n unverify: 'listed',\n}\n\n/**\n * One listing in full, for the detail page (AGL-959). The index deals in\n * rows; everything a reviewer needs to actually decide — manifest,\n * capabilities, ABI, verifier findings, per-version trust, takedown state —\n * is assembled here rather than smeared across the list payload.\n */\nasync function listingDetail(\n firestore: FirebaseFirestore.Firestore,\n listingId: string,\n requestedVersion?: string,\n): Promise<Response> {\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const snapshot = await listingRef.get()\n const listing = snapshot.data()\n if (!listing) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n\n const versionsSnapshot = await listingRef\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(25)\n .get()\n const versions = versionsSnapshot.docs.map((doc) => {\n const publishedAt = doc.get('publishedAt')\n return {\n version: String(doc.get('version') ?? doc.id),\n trust: doc.get('trust') ?? null,\n sha256: String(doc.get('sha256') ?? ''),\n hostAbi: Number(doc.get('manifest.hostAbi')) || null,\n capabilities: doc.get('manifest.capabilities') ?? {},\n // What these bytes declare they contribute (AGL-3116); `null` when the\n // version predates the contract and loads under its default.\n contributes: readPluginContributions(doc.get('manifest.contributes')) ?? null,\n // Declared canvas elements (AGL-1031), for THESE bytes. Publisher copy\n // that renders in the customer's element picker and nowhere on the\n // listing page — so without it here, the `element-metadata` criterion\n // asks a reviewer to check text this page never shows (AGL-2486).\n elements: doc.get('manifest.elements') ?? [],\n publishedAt: publishedAt?.toDate?.()?.toISOString() ?? null,\n // Per-version installs (AGL-1036). \"How many workspaces would a revoke\n // actually hit\" is a per-version question, and the listing total shown\n // elsewhere on this page answers a different one.\n installCount: Number(doc.get('installCount') ?? 0),\n activeInstalls: Number(doc.get('activeInstalls') ?? 0),\n signed: Boolean(doc.get('signature')),\n // The repo as declared for THESE bytes (AGL-1076); absent on versions\n // published before it was collected.\n repositoryUrl: String(doc.get('repositoryUrl') ?? ''),\n reviewState: String(doc.get('reviewState') ?? 'pending'),\n grandfathered: Boolean(doc.get('grandfathered')),\n // Server-side only — used to decide whether the verdict below needs\n // recomputing; stripped before the payload goes out.\n verification: doc.get('verification') ?? null,\n reviewChecklist: doc.get('reviewChecklist') ?? null,\n publisherAttestation: doc.get('publisherAttestation') ?? null,\n }\n })\n\n // Publisher is an ORG since AGL-652 — show the name, not the raw id.\n const publisherId = String(listing.profileId ?? '')\n const publisher = publisherId\n ? await firestore.collection('orgs').doc(publisherId).get()\n : null\n\n // Which terms this publisher is actually under (AGL-1077). A reviewer\n // weighing a takedown, a delist, or a revocation is deciding what we are\n // entitled to do — and that is answered by the agreement the ORG accepted,\n // not by the per-version attestation beside it.\n const publisherProfile = publisherId\n ? await firestore.collection('publisherProfiles').doc(publisherId).get()\n : null\n const acceptance = publisherProfile?.get('publisherAgreement') as\n | { version?: string; acceptedBy?: string; acceptedAt?: { toDate?: () => Date } }\n | undefined\n\n // Kill switch, so the page can say whether the plugin is actually stopped\n // rather than only de-listed (AGL-948).\n const revocation = (\n await firestore.collection('revocations').doc(listingId).get()\n ).data()\n\n // The verifier verdict for the version under review (AGL-426), served\n // from the version doc when it is current (AGL-962).\n //\n // `checkPluginBundle` is pure and the artifact is immutable and\n // content-addressed, so a verdict pinned to {sha256, verifierVersion} is\n // exactly as trustworthy as re-running it — and re-running meant\n // downloading up to a megabyte from Storage on EVERY page view. A stored\n // verdict from an older checker, or for different bytes, is ignored.\n // Which version this page is reviewing (AGL-966). Defaults to the oldest\n // version still awaiting a verdict — that is the work — falling back to\n // the latest when everything is decided. A reviewer can pin any version\n // explicitly; the checklist and verifier verdict follow the selection,\n // because both are statements about specific bytes.\n const pendingFirst = [...versions]\n .reverse()\n .find((entry) => entry.reviewState !== 'approved')\n const reviewVersion =\n (requestedVersion &&\n versions.find((entry) => entry.version === requestedVersion)?.version) ||\n pendingFirst?.version ||\n String(listing.latestVersion ?? '')\n const artifactsBucket = process.env.PLUGIN_ARTIFACTS_BUCKET\n const reviewEntry = versions.find((entry) => entry.version === reviewVersion)\n const reviewSha = reviewEntry?.sha256\n const stored = reviewEntry?.verification as StoredBundleVerdict | undefined\n const storedIsCurrent = isStoredVerdictCurrent(stored, reviewSha ?? '')\n\n let verifier: unknown = storedIsCurrent\n ? {\n ok: stored?.ok,\n problems: stored?.problems ?? [],\n // The per-check summary rides along in the stored verdict (AGL-1087)\n // so the page can show what was checked without re-downloading a\n // megabyte of artifact on every view.\n checks: stored?.checks ?? [],\n }\n : null\n let verifierCached = storedIsCurrent\n if (!storedIsCurrent && artifactsBucket && reviewSha) {\n try {\n const [bytes] = await firebaseAdmin\n .app()\n .storage()\n .bucket(artifactsBucket)\n .file(pluginArtifactPath(listingId, reviewVersion, reviewSha))\n .download()\n // The manifest for THESE bytes, so an undeclared network call is a\n // finding rather than a warning (AGL-964). Read from the version doc,\n // never from the listing — capabilities change between versions.\n const result = checkPluginBundle(bytes.toString('utf8'), {\n declaredNetwork: Array.isArray(reviewEntry?.capabilities?.network)\n ? reviewEntry.capabilities.network.map((origin: unknown) =>\n String(origin),\n )\n : [],\n // Compared, never required: a version published before the contract\n // loads under its default, and review must not refuse it for a rule\n // it was never held to.\n declaredContributions: reviewEntry?.contributes ?? null,\n })\n verifier = result\n // Write it back so this sha is verified at most once platform-wide —\n // covers every listing published before the verdict was persisted at\n // publish time, and any version whose checker has since moved on.\n // Best effort: a failed write costs the next reader a re-run, nothing\n // more, so it must never fail the page.\n await listingRef\n .collection('pluginVersions')\n .doc(reviewVersion)\n .set(\n {\n verification: {\n ok: result.ok,\n problems: result.problems,\n checks: result.checks,\n sha256: reviewSha,\n verifierVersion: PLUGIN_VERIFIER_VERSION,\n checkedAt: FieldValue.serverTimestamp(),\n },\n },\n { merge: true },\n )\n .catch(() => undefined)\n } catch {\n verifier = { error: 'artifact unavailable' }\n verifierCached = false\n }\n }\n\n // Who attested, by name (AGL-969). \"A named publisher said this on a date\"\n // is the half that makes a false attestation actionable, and a raw uid\n // names nobody. Best effort — a deleted account must not blank the page.\n const attestationEntries = Object.values(\n (reviewEntry?.publisherAttestation ?? {}) as Record<\n string,\n { by?: string; at?: { toDate?: () => Date }; sha256?: string }\n >,\n ).filter((entry) => entry?.sha256 === reviewSha)\n const attesterUid = attestationEntries.find((entry) => entry.by)?.by\n const attestedAt =\n attestationEntries.find((entry) => entry.at)?.at?.toDate?.()?.toISOString() ??\n null\n let attestedBy: string | null = attesterUid ?? null\n if (attesterUid) {\n try {\n // Across pools (AGL-1122): an SSO attester is invisible to project-level\n // `getUser`, so this fell through to the catch and the review page named\n // the attester by raw uid — indistinguishable from \"account deleted\".\n const found = await findUserByUidAcrossPools(attesterUid)\n if (found) {\n attestedBy =\n found.record.email ?? found.record.displayName ?? attesterUid\n }\n } catch {\n // Account gone — the uid still identifies the statement.\n }\n }\n\n return Response.json(\n {\n listingId,\n displayName: listing.displayName ?? listingId,\n description: listing.description ?? '',\n // The publisher's ask, so the page can offer Decline beside Verify\n // (AGL-1217). Serialized: `decidedAt`/`requestedAt` are Timestamps and\n // this payload crosses JSON.\n verificationRequest: listing.verificationRequest\n ? {\n state: String(listing.verificationRequest.state ?? ''),\n requestedAt:\n listing.verificationRequest.requestedAt?.toDate?.()?.toISOString() ??\n null,\n declineReason: listing.verificationRequest.declineReason ?? null,\n }\n : null,\n readme: listing.readme ?? '',\n license: listing.license ?? '',\n categories: listing.categories ?? [],\n homepageUrl: listing.homepageUrl ?? '',\n // Prefer what the version under review declared (AGL-1076). The\n // listing carries whatever the most recent publish said, and a repo\n // can move between versions — the link a reviewer opens should be the\n // one attested against the bytes in front of them. Falls back to the\n // listing for versions published before this was collected.\n repositoryUrl: reviewEntry?.repositoryUrl || listing.repositoryUrl || '',\n publisherId,\n publisherName: publisher?.get('name') ?? publisherId,\n publisherSlug: publisher?.get('slug') ?? null,\n reviewStatus: listing.reviewStatus ?? 'submitted',\n rejectionReason: listing.rejectionReason ?? '',\n rejectionCategory: listing.rejectionCategory ?? '',\n priceUsd: Number(listing.priceUsd ?? 0),\n latestVersion: String(listing.latestVersion ?? ''),\n // The version the checklist, verifier verdict and approve/reject\n // actions on this payload refer to.\n reviewVersion,\n activeInstalls: Number(listing.activeInstalls ?? 0),\n hidden: Boolean(listing.hiddenAt),\n hiddenReason: String(listing.hiddenReason ?? ''),\n revoked: Boolean(revocation),\n revokedVersions: revocation?.versions ?? null,\n unpublished: Boolean(listing.deletedAt),\n private: listing.visibility === 'private',\n platformHostAbi: PLUGIN_HOST_ABI_VERSION,\n // Where the bundle bytes actually live (AGL-990). Staff-only payload,\n // and a bucket NAME is not a credential — reaching the object still\n // needs a Google account with access. Without it the page cannot build\n // a Cloud console link, and this bucket does not appear in the Firebase\n // console at all, so a reviewer has no way to find it by hand.\n artifactsBucket: artifactsBucket ?? null,\n versions: versions.map(\n // The rest-strip is the point: `verification`, `reviewChecklist` and\n // `publisherAttestation` are named only so they DO NOT reach the\n // client payload, which is what the disable below is for. The\n // duplicate directive that used to sit above `versions.map(` covered\n // a line with nothing unused on it, and this config treats an\n // unused disable as a failure.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ({ verification, reviewChecklist, publisherAttestation, ...entry }) => ({\n ...entry,\n // Per-version kill-switch state (AGL-1085), read through the same\n // helper the loaders use so the page cannot disagree with the\n // runtime about whether these bytes are stopped.\n revoked: isPluginRevoked(\n revocation as PluginRevocation | undefined,\n entry.version,\n ),\n }),\n ),\n // Review checklist for the version under review (AGL-963). Ticks made\n // against different bytes do not count, so a republish starts clean.\n checklist: Object.fromEntries(\n Object.entries(\n (reviewEntry?.reviewChecklist ?? {}) as Record<\n string,\n { by?: string; sha256?: string }\n >,\n )\n .filter(([, entry]) => entry?.sha256 === reviewSha)\n .map(([id, entry]) => [id, { by: entry.by ?? null }]),\n ),\n checklistOutstanding: outstandingChecklistItems(\n reviewEntry?.reviewChecklist as never,\n reviewSha ?? '',\n ),\n // What the publisher stated about THESE bytes (AGL-969). Not a review\n // input — a reviewer still checks everything themselves — but it says\n // what was claimed, so a discrepancy is a documented false statement\n // rather than a difference of opinion. Attestations recorded against\n // other bytes are dropped, exactly like staff ticks.\n attestation: attestationsForBytes(\n reviewEntry?.publisherAttestation as never,\n reviewSha ?? '',\n ),\n attestedBy,\n attestedAt,\n // The publisher agreement this ORG is under (AGL-1077). `current` is\n // computed here rather than shipped as a boolean so the page can say\n // \"on an older version\" — which is a different thing from never\n // having accepted, and matters differently to a takedown decision.\n publisherAgreement: {\n version: acceptance?.version ?? null,\n acceptedAt: acceptance?.acceptedAt?.toDate?.()?.toISOString() ?? null,\n required: PUBLISHER_AGREEMENT_VERSION,\n state: publisherAgreementState(acceptance),\n },\n verifier,\n verifierCached,\n verifierVersion: PLUGIN_VERIFIER_VERSION,\n },\n { status: 200 },\n )\n}\n\n/**\n * Re-derive `latestApprovedVersion` from the versions themselves (AGL-2306).\n *\n * The mirror was written on approval only, with a comment saying it \"only ever\n * moves forward\" — true of approvals, and the reason it is there. What nothing\n * did was move it BACK. A version approved and later rejected on re-review, or\n * killed with the per-version switch, left the listing still advertising it:\n * `host-plugins-card` and `marketplace-update-state` read this field to offer\n * \"Update to vX\", and `install-plugin` would then refuse those exact bytes.\n *\n * Contained, because `install-plugin` recomputes approval live and never\n * trusts this field — no unreviewed or revoked bytes could ship — but it is\n * the AGL-1016 guarantee leaking back out through a badge, which is where\n * AGL-966 came in.\n *\n * Recomputed rather than decremented: \"the newest version that is approved AND\n * not revoked\" is a property of the whole set, and stepping it back one at a\n * time is how a mirror drifts in the other direction.\n *\n * Revoked versions are excluded because the offer has to be installable, and\n * `install-plugin` 409s on a revoked pin. That also makes un-revoking restore\n * the offer, which is why this runs on both revoke and unrevoke.\n *\n * Deletes the field when nothing qualifies: an absent mirror reads as \"no\n * update to offer\", while a stale string reads as an update that does not\n * exist.\n */\nasync function repairLatestApprovedVersion(\n listingRef: FirebaseFirestore.DocumentReference,\n revocation: PluginRevocation | null | undefined,\n): Promise<void> {\n const versions = await listingRef\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(50)\n .get()\n // The DECISION lives in core (`newestInstallableVersion`), where it is\n // testable without a Firestore double and shared with anything else that\n // has to answer \"what is on offer\". This function is only the query.\n const newest = newestInstallableVersion(\n versions.docs.map((doc) => ({\n version: doc.id,\n reviewState: doc.get('reviewState'),\n })),\n revocation,\n compareArtifactVersions,\n )\n await updateExisting(listingRef, {\n latestApprovedVersion: newest ?? FieldValue.delete(),\n updatedAt: FieldValue.serverTimestamp(),\n })\n}\n\nasync function handler(request: Request): Promise<Response> {\n const { method, body, query, headers: rawHeaders } =\n await pluginRequestFromWeb(request)\n const headers = rawHeaders as Partial<Record<string, string>>\n const authorization = headers.authorization ?? ''\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return Response.json({ error: 'Unauthenticated' }, { status: 401 })\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n if (!decoded.email_verified && !isImpersonationSession(decoded)) {\n return emailUnverifiedResponse()\n }\n if (!decoded['staff']) {\n return Response.json({ error: 'Staff only' }, { status: 403 })\n }\n const firestore = firebaseAdmin.app().firestore()\n\n if (method === 'GET') {\n const detailId = String(query['listingId'] ?? '')\n if (detailId) {\n return listingDetail(firestore, detailId, String(query['version'] ?? ''))\n }\n\n // Every plugin listing, bucketed by whether its newest bytes are\n // waiting on a reviewer (AGL-966). The queue used to ask only for\n // `reviewStatus in ['submitted','in_review']`, which meant an UPDATE\n // to an already-listed plugin appeared nowhere: the listing kept its\n // status, so nobody was ever shown the new version. Reading each\n // listing's latest version doc costs one read per listing and needs\n // no new composite index.\n const snapshot = await firestore\n .collection('marketplaceListings')\n .where('type', '==', 'plugin')\n .limit(100)\n .get()\n // Rows only (AGL-961). This used to DOWNLOAD every queued bundle to\n // re-run the verifier, so the index paid a Storage round trip per\n // submission before it could paint. The verifier now runs on the\n // detail page, for the one listing being read.\n const rows = await Promise.all(\n snapshot.docs\n .filter((doc) => !doc.get('deletedAt'))\n .map(async (doc) => {\n const listing = doc.data()\n const version = String(listing.latestVersion ?? '')\n const latest = version\n ? await doc.ref.collection('pluginVersions').doc(version).get()\n : null\n return {\n listingId: doc.id,\n displayName: listing.displayName ?? doc.id,\n description: listing.description ?? '',\n license: listing.license ?? '',\n categories: listing.categories ?? [],\n profileId: listing.profileId,\n reviewStatus: listing.reviewStatus ?? 'submitted',\n priceUsd: Number(listing.priceUsd ?? 0),\n version,\n hidden: Boolean(listing.hiddenAt),\n private: listing.visibility === 'private',\n latestReviewState: String(latest?.get('reviewState') ?? 'pending'),\n grandfathered: Boolean(latest?.get('grandfathered')),\n // The publisher's standing ask for the badge (AGL-1217).\n verificationRequest: listing.verificationRequest ?? null,\n }\n }),\n )\n // Awaiting review = the newest bytes have no approval, whatever the\n // listing says. That is what puts an update in front of staff.\n const queue = rows.filter((row) => row.latestReviewState !== 'approved')\n // A THIRD bucket, deliberately not folded into `queue` (AGL-1217).\n // `queue` means \"these bytes have not been read\"; a verification request\n // means \"this publisher asked us to vouch for who they are\". They are\n // different questions with different work attached, and a listing can\n // sit in both at once — an update pending review from a publisher who\n // has also asked for the badge. Merging them would hide one behind the\n // other and make the count meaningless.\n const verificationRequests = rows.filter(\n (row) => row.verificationRequest?.state === 'pending',\n )\n // Listed/verified plugins with per-version trust (AGL-885): once a\n // listing leaves the queue the Grant/Revoke realm-trust actions used\n // to leave with it — revoking a live plugin's trust required a\n // hand-crafted API call. This block keeps every listed plugin's\n // version trust state administrable.\n const listedSnapshot = {\n docs: snapshot.docs.filter((doc) =>\n ['listed', 'verified'].includes(String(doc.get('reviewStatus') ?? '')),\n ),\n }\n const listed = await Promise.all(\n listedSnapshot.docs.map(async (doc) => {\n const listing = doc.data()\n const versionsSnapshot = await doc.ref\n .collection('pluginVersions')\n .orderBy('publishedAt', 'desc')\n .limit(10)\n .get()\n const versions = versionsSnapshot.docs.map((versionDoc) => ({\n version: String(versionDoc.get('version') ?? versionDoc.id),\n trust: versionDoc.get('trust') ?? null,\n reviewState: String(versionDoc.get('reviewState') ?? 'pending'),\n }))\n return {\n listingId: doc.id,\n displayName: listing.displayName ?? doc.id,\n reviewStatus: listing.reviewStatus,\n profileId: listing.profileId,\n latestVersion: String(listing.latestVersion ?? ''),\n // Takedown state (AGL-952), so a row shows the current verdict\n // rather than sending a reviewer into the detail page to find\n // out whether the plugin is stopped.\n hidden: Boolean(listing.hiddenAt),\n hiddenReason: String(listing.hiddenReason ?? ''),\n private: listing.visibility === 'private',\n pendingVersions: versions.filter(\n (entry) => entry.reviewState !== 'approved',\n ).length,\n // Summarised for the row; the per-version controls live on the\n // detail page (AGL-960).\n realmVersions: versions.filter((entry) => entry.trust === 'realm')\n .length,\n versionCount: versions.length,\n versions,\n }\n }),\n )\n\n // Publisher names for scanning (AGL-961) — a listing id tells a\n // reviewer nothing. One batched read for both sections.\n const publisherIds = [\n ...new Set(\n [...queue, ...listed]\n .map((entry) => String(entry.profileId ?? ''))\n .filter(Boolean),\n ),\n ]\n const publishers: Record<string, string> = {}\n if (publisherIds.length) {\n const docs = await firestore.getAll(\n ...publisherIds.map((id) => firestore.collection('orgs').doc(id)),\n )\n for (const doc of docs) {\n if (doc.exists) publishers[doc.id] = String(doc.get('name') ?? doc.id)\n }\n }\n return Response.json(\n { queue, listed, publishers, verificationRequests },\n { status: 200 },\n )\n }\n\n if (method !== 'POST') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n const listingId = String(body?.listingId ?? '')\n const action = String(body?.action ?? '')\n\n // Takedown (AGL-658) is separate from the review verdict: it applies to\n // EVERY artifact type, not just plugins, and it must not overwrite a\n // plugin's `reviewStatus` — a hidden plugin that later gets un-hidden\n // should return to the verdict it had, not to square one.\n if (action === 'hide' || action === 'unhide') {\n if (!listingId) {\n return Response.json({ error: 'Missing listingId' }, { status: 400 })\n }\n const hideReason = String(body?.reason ?? '').slice(0, 500)\n if (action === 'hide' && !hideReason.trim()) {\n return Response.json({ error: 'Hiding needs a reason' }, { status: 400 })\n }\n const reviewUid = String(body?.reviewUid ?? '')\n const target = reviewUid\n ? firestore\n .collection('marketplaceListings')\n .doc(listingId)\n .collection('reviews')\n .doc(reviewUid)\n : firestore.collection('marketplaceListings').doc(listingId)\n const targetSnapshot = await target.get()\n if (!targetSnapshot.exists) {\n return Response.json({ error: 'Unknown target' }, { status: 404 })\n }\n // A takedown strips the Verified badge (AGL-1121, decided 2026-08-03).\n //\n // Verified is OUR claim that a human vouched for this publisher. Taking\n // the listing down is us saying the opposite out loud, so the two cannot\n // both stand — a badge surviving a takedown would still be asserting the\n // vouch on the listing page the moment it was restored.\n //\n // Demoted to `listed`, not to `rejected` or `submitted`: the takedown\n // itself is what makes it non-browsable (`hiddenAt`), and rewriting the\n // review verdict would destroy the record of a review that did happen.\n //\n // Restoring deliberately does NOT put the badge back. Re-granting is\n // `verify`, which re-checks the review checklist server-side; an automatic\n // regrant would hand back the badge without anyone re-forming the opinion\n // behind it. Losing it to a takedown is meant to cost a re-review.\n const stripVerified = shouldStripVerifiedOnTakedown({\n action,\n reviewStatus: targetSnapshot.get('reviewStatus'),\n isListingTarget: !reviewUid,\n })\n await target.set(\n reviewUid\n ? { hidden: action === 'hide' }\n : action === 'hide'\n ? {\n hiddenAt: FieldValue.serverTimestamp(),\n hiddenBy: decoded.uid,\n hiddenReason: hideReason,\n ...(stripVerified\n ? { reviewStatus: VERIFIED_STRIPPED_STATUS }\n : {}),\n }\n : {\n hiddenAt: FieldValue.delete(),\n hiddenBy: FieldValue.delete(),\n hiddenReason: FieldValue.delete(),\n },\n { merge: true },\n )\n\n // Takedown means takedown (AGL-948). Hiding a PLUGIN listing also\n // writes the kill switch, so one staff action has one outcome\n // instead of leaving the bundle executing in every workspace that\n // already installed it. The realm join blocks on `hiddenAt` too, but\n // the revocation is what the client-side loaders and the public\n // listing-versions endpoint already understand — belt and braces on\n // the one action where a gap means running attacker code.\n const isPlugin =\n !reviewUid &&\n (targetSnapshot.get('artifactType') === 'plugin' ||\n targetSnapshot.get('type') === 'plugin')\n /**\n * An email starter earns the same treatment for the same reason.\n *\n * It is copied on install, so `hiddenAt` alone reaches only the\n * storefront: every tenant who already installed it goes on MAILING it,\n * from the sending domain every other tenant shares. The revocation is\n * what `emailStarterSendBlock` reads at the send, which is the only\n * chokepoint that can still refuse.\n *\n * The five other copied types are deliberately not here. Their content\n * is rendered on the tenant's own site, where `hiddenAt` blocking the\n * next install is the whole of what a takedown can honestly promise —\n * stopping a page from rendering is a different decision, and one nobody\n * has made.\n */\n const killsInstalledCopies =\n isPlugin ||\n (!reviewUid && targetSnapshot.get('artifactType') === 'emailStarter')\n if (killsInstalledCopies) {\n const revocationRef = firestore.collection('revocations').doc(listingId)\n const current = (await revocationRef.get()).data() as\n | PluginRevocation\n | undefined\n // Both transitions go through the shared helper (AGL-1085) so a\n // takedown and a per-version review revocation can coexist. Restoring\n // used to DELETE the doc whenever it was takedown-owned, which also\n // un-revoked any version a reviewer had stopped for an unrelated\n // reason — `reviewVersions` is what survives the round trip.\n const next = nextRevocationState(current, {\n type: action === 'hide' ? 'takedown' : 'restore',\n })\n if (next) {\n await revocationRef.set(\n {\n ...next,\n ...(action === 'hide' ? { reason: hideReason } : {}),\n revokedBy: decoded.uid,\n revokedAt: FieldValue.serverTimestamp(),\n // A restore drops takedown ownership; the field has to go, not\n // merely be overwritten, or the next restore re-deletes.\n ...(action === 'hide' ? {} : { source: FieldValue.delete() }),\n },\n { merge: true },\n )\n } else if (current) {\n await revocationRef.delete()\n }\n // Make the kill switch reach ALREADY-CACHED pages (AGL-1152). The\n // tenant stamps each plugin node with its revocation state at compose\n // time, so without this the bundle we just killed keeps executing on\n // every cached page until it happens to re-render. Best effort: the\n // tenant refuses a revoked plugin at render time regardless.\n //\n // Plugin-only: it walks the plugin INSTALL PINS, which an email\n // starter has none of, and an email is never part of a cached page —\n // its kill is felt at the send, where nothing is cached.\n if (isPlugin) await dropCachesForListing(firestore, listingId)\n // The offer follows the kill switch here too (AGL-2368). AGL-2306\n // taught the per-version revoke and the reject path to repair the\n // mirror and left this one out, so a takedown flattened `versions` to\n // `'all'` — revoking every build — while `latestApprovedVersion` went\n // on naming one. `hiddenAt` hides the listing from browse and blocks\n // the install route, so nothing was installable through it; but a\n // restore clears `hiddenAt` first and the mirror is what the update\n // badges read, and `nextRevocationState` can return a document that\n // still holds a reviewer's per-version revocations. Recomputed from\n // the versions in both directions rather than reasoned about.\n //\n // Named explicitly rather than reusing `target`: `isPlugin` is only\n // true when `reviewUid` is empty, so they are the same document — but\n // that is a fact two conditions apart, and a repair pointed at a\n // review subdocument would write a `latestApprovedVersion` onto it.\n //\n // Plugin-only, unlike the revocation write above: the mirror is\n // recomputed from `pluginVersions`, a collection no other artifact\n // type has, so running it for an email starter would derive \"nothing\n // approved\" from an empty read and write that over the listing.\n if (isPlugin) {\n await repairLatestApprovedVersion(\n firestore.collection('marketplaceListings').doc(listingId),\n next,\n )\n }\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.takedown.${action}`,\n target: reviewUid\n ? `marketplaceListings/${listingId}/reviews/${reviewUid}`\n : `marketplaceListings/${listingId}`,\n /*\n * A review document is keyed by its AUTHOR's uid, so hiding one is a\n * staff act against a named person. The target names the review, as\n * it must — but on its own that put the takedown nowhere near the\n * page of the person whose words were removed.\n */\n ...(reviewUid ? { subjectUid: reviewUid } : {}),\n after: {\n hidden: action === 'hide',\n ...(hideReason ? { reason: hideReason } : {}),\n ...(killsInstalledCopies ? { revoked: action === 'hide' } : {}),\n // Recorded because it is a side effect of the takedown rather than\n // something the reviewer asked for, and because getting it back is a\n // re-review rather than an undo.\n ...(stripVerified ? { unverified: true } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n return Response.json(\n {\n ok: true,\n hidden: action === 'hide',\n revoked: killsInstalledCopies && action === 'hide',\n // The caller shows this — a badge silently disappearing would be\n // worse than one that never existed.\n unverified: stripVerified,\n },\n { status: 200 },\n )\n }\n\n // Review checklist (AGL-963). Ticks are per {version, sha256} and carry\n // who + when, so \"verified\" is a recorded act rather than a click.\n if (action === 'checklist') {\n const version = String(body?.version ?? '')\n const itemId = String(body?.itemId ?? '')\n const checked = body?.checked !== false\n if (!listingId || !version || !REQUIRED_OR_OPTIONAL.has(itemId)) {\n return Response.json({ error: 'Unknown checklist item' }, { status: 400 })\n }\n const versionRef = firestore\n .collection('marketplaceListings')\n .doc(listingId)\n .collection('pluginVersions')\n .doc(version)\n const versionSnapshot = await versionRef.get()\n if (!versionSnapshot.exists) {\n return Response.json({ error: 'Unknown version' }, { status: 404 })\n }\n await versionRef.set(\n {\n reviewChecklist: {\n [itemId]: checked\n ? {\n by: decoded.uid,\n at: FieldValue.serverTimestamp(),\n // Pins the tick to the bytes it was made against.\n sha256: String(versionSnapshot.get('sha256') ?? ''),\n }\n : FieldValue.delete(),\n },\n },\n { merge: true },\n )\n // Audited (AGL-971): a checklist tick is the record that a human\n // looked, so it needs the same trail as the verdict it unlocks —\n // including WHICH bytes were looked at.\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.checklist.${checked ? 'check' : 'uncheck'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n itemId,\n checked,\n sha256: String(versionSnapshot.get('sha256') ?? ''),\n },\n at: FieldValue.serverTimestamp(),\n })\n return Response.json({ ok: true, itemId, checked }, { status: 200 })\n }\n\n // Per-version verdicts (AGL-966). Approval is a statement about bytes,\n // so it lives on the version doc and installs resolve the newest\n // approved one. Listing-level list/verify still exist, but they can no\n // longer ship code past review on their own.\n if (action === 'approve-version' || action === 'reject-version') {\n const version = String(body?.version ?? '')\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const versionRef = listingRef.collection('pluginVersions').doc(version)\n const versionSnapshot = await versionRef.get()\n if (!versionSnapshot.exists) {\n return Response.json({ error: 'Unknown version' }, { status: 404 })\n }\n // The LISTING has to exist too, and the check belongs up here rather\n // than beside the writes that need it (AGL-1766). A version outliving\n // its listing is not hypothetical — Firestore deletes are not\n // recursive, so `pluginVersions` survives whatever removed the parent.\n //\n // The read below used to be `(await listingRef.get()).data() ?? {}`,\n // and that default was not a convenience: it is what made the two\n // mirrors fire. Both of their conditions are TRUE on `{}` —\n // `!['listed','verified'].includes('')` and `previous == null` — so an\n // absent listing was resurrected as `{ reviewStatus: 'listed' }`, i.e.\n // browsable in the marketplace, from a merge-set. (The third mirror,\n // `latestVersionReviewState`, compares `String(latestVersion ?? '')`\n // against a non-empty `version` and is false on `{}` — it could not\n // fire. The pattern is not uniform even inside one block, which is\n // exactly why AGL-1763 could not express this as a lint rule.)\n //\n // Read BEFORE the verdict write, not after it. Refusing must not\n // discard work that already happened (AGL-1760); refusing here happens\n // before anything has, so the reviewer simply retries against a\n // listing that exists. `?? {}` is gone with it — kept, it would have\n // traded a resurrection for an `update()` rejection served as a 500.\n const listingSnapshot = await listingRef.get()\n if (!listingSnapshot.exists) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n const listing = listingSnapshot.data()\n const sha256 = String(versionSnapshot.get('sha256') ?? '')\n const approving = action === 'approve-version'\n if (approving) {\n const outstanding = outstandingChecklistItems(\n versionSnapshot.get('reviewChecklist'),\n sha256,\n )\n if (outstanding.length) {\n return Response.json(\n {\n error: `Review checklist incomplete — ${outstanding.length} required item(s) outstanding for these bytes`,\n outstanding,\n },\n { status: 409 },\n )\n }\n }\n const reason = String(body?.reason ?? '').slice(0, 500)\n // Structured rejection (AGL-977). The category is what makes rejections\n // comparable across reviewers and queryable afterwards; the comment is\n // what makes one actionable. Requiring only free text gave neither.\n const category = String(body?.category ?? '')\n if (!approving) {\n const invalid = rejectionInputError(category, reason)\n if (invalid) return Response.json({ error: invalid }, { status: 400 })\n }\n await versionRef.set(\n {\n reviewState: approving ? 'approved' : 'rejected',\n reviewedBy: decoded.uid,\n reviewedAt: FieldValue.serverTimestamp(),\n // Records WHICH bytes were approved, so a later republish under\n // the same version string can never inherit this verdict.\n reviewedSha256: sha256,\n grandfathered: FieldValue.delete(),\n ...(approving\n ? {\n // Clear a previous rejection's fields on approval, or a\n // version that was rejected and then approved keeps\n // explaining why it was turned down.\n reviewRejectionReason: FieldValue.delete(),\n reviewRejectionCategory: FieldValue.delete(),\n }\n : {\n reviewRejectionReason: reason,\n reviewRejectionCategory: category,\n // REALM TRUST IS WITHDRAWN WITH THE APPROVAL (AGL-2306).\n //\n // `admin-trust` refuses to grant `trust: 'realm'` unless the\n // version is approved — approval gates the grant. Nothing\n // ungated it: the realm load path checks `hiddenAt`, the sha,\n // the signature and the revocation, and never re-reads\n // `reviewState`. So approve → sign → re-review → reject left\n // the version loading IN THE APP REALM, where neither the\n // sandbox iframe nor the plugin-origin CSP is between it and\n // user data, until staff separately reached for the kill\n // switch.\n //\n // The same four fields `admin-trust`'s own revoke branch\n // clears, so there is one shape of \"untrusted\" rather than\n // two. This does NOT stop the bundle running as a sandboxed\n // plugin — that is what the per-version revocation beside\n // this decision is for, and it is deliberately a separate\n // choice (a thin README is the usual rejection, and an\n // unannounced site outage is worse). It withdraws only the\n // privilege that approval was the precondition for.\n trust: FieldValue.delete(),\n signature: FieldValue.delete(),\n trustGrantedBy: FieldValue.delete(),\n trustGrantedAt: FieldValue.delete(),\n }),\n },\n { merge: true },\n )\n\n // A plugin with its first approved version becomes browsable. Later\n // approvals never change listing status — that is the point: an\n // update is reviewed without disturbing what customers already have.\n //\n // The three mirrors below write through `updateExisting` as the second\n // line for the window the check above cannot close — a listing deleted\n // mid-handler. Every payload here is FLAT with no delete sentinel, so\n // the switch is semantically identical to the merge-set it replaces;\n // the `false` return needs no branch, because a listing that is gone by\n // now wants nothing mirrored onto it.\n\n // Mirror this verdict onto the listing for the marketplace (AGL-1121),\n // but ONLY when it is the newest version. Approving an old version\n // must not let the listing claim its newest bytes were reviewed —\n // which is the exact shape of the bug this mirror exists to fix.\n if (String(listing.latestVersion ?? '') === version) {\n await updateExisting(listingRef, {\n latestVersionReviewState: approving ? 'approved' : 'rejected',\n })\n }\n if (\n approving &&\n !['listed', 'verified'].includes(String(listing.reviewStatus ?? ''))\n ) {\n await updateExisting(listingRef, {\n reviewStatus: 'listed',\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n\n // Denormalise the newest approved version onto the listing (AGL-1016).\n // `pluginVersions` is server-only, so a console showing \"update\n // available\" has nothing else to read — and reading `latestVersion`\n // instead would advertise a version the install route refuses, leaking\n // AGL-966's guarantee back out through a badge.\n //\n // Only ever moves forward: approving an older version after a newer one\n // is a real sequence (a reviewer working through a backlog) and must not\n // walk the offer backwards.\n if (approving) {\n const previous = listing.latestApprovedVersion\n if (\n previous == null ||\n (compareArtifactVersions(String(previous), version) ?? 0) < 0\n ) {\n await updateExisting(listingRef, {\n latestApprovedVersion: version,\n updatedAt: FieldValue.serverTimestamp(),\n })\n }\n } else if (String(listing.latestApprovedVersion ?? '') === version) {\n // …and BACK when the version being offered is the one just rejected\n // (AGL-2306). Nothing did this, so a re-review that turned a live\n // version down left the listing advertising it — an \"Update to vX\"\n // for bytes `install-plugin` answers 409 to.\n const revocation = (\n await firestore.collection('revocations').doc(listingId).get()\n ).data() as PluginRevocation | undefined\n await repairLatestApprovedVersion(listingRef, revocation)\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.version.${approving ? 'approve' : 'reject'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n sha256,\n ...(reason ? { reason } : {}),\n // Both, not one (AGL-971 + AGL-977): the category is what an audit\n // can be counted by, the comment is what makes a single row make\n // sense to a human reading it later.\n ...(category ? { category } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n // Pins sitting on these exact bytes right now (AGL-1085). Rejecting a\n // version does NOT stop it — the runtime resolves a pin by\n // {version, sha256} and only asks whether it is revoked — so both\n // sides have to be told, and the reviewer needs the number before\n // deciding whether to reach for the kill switch.\n const liveInstalls = Number(versionSnapshot.get('activeInstalls') ?? 0)\n const stranded = !approving && liveInstalls > 0\n\n if (listing.profileId) {\n await notifyOrgAdmins(String(listing.profileId), {\n type: 'marketplace.review',\n title: approving\n ? `\"${listing.displayName}\" v${version} approved`\n : `\"${listing.displayName}\" v${version} was not approved`,\n body: approving\n ? 'It is now the version new installs receive.'\n : stranded\n ? `${reason}\\n\\nThis version is still installed on ` +\n `${liveInstalls} site${liveInstalls === 1 ? '' : 's'}. ` +\n 'Rejecting it does not remove it — uninstall or roll back.'\n : reason,\n orgId: String(listing.profileId),\n link: '/',\n }).catch(() => undefined)\n await emailPublisher(\n String(listing.profileId),\n approving\n ? `${listing.displayName} v${version} passed review`\n : `${listing.displayName} v${version} was not approved`,\n approving\n ? `Your plugin version ${version} has been approved and is now ` +\n 'the version new installs receive. Existing installs stay on ' +\n 'the version they pinned until their site owners upgrade.'\n : `Your plugin version ${version} was not approved.\\n\\n` +\n `Reason: ${reason}\\n\\nPublishing a new version puts it back ` +\n 'in the review queue. The previously approved version, if any, ' +\n 'keeps installing in the meantime.' +\n (stranded\n ? `\\n\\nNote: v${version} is still installed on ` +\n `${liveInstalls} site${liveInstalls === 1 ? '' : 's'}. ` +\n 'A rejection stops new installs, it does not remove an ' +\n 'existing one — uninstall it or roll back to an approved ' +\n 'version.'\n : ''),\n )\n }\n\n return Response.json(\n {\n ok: true,\n version,\n reviewState: approving ? 'approved' : 'rejected',\n // Lets the reviewer's confirmation say what it actually did, and\n // offer the kill switch when the bytes are live somewhere.\n liveInstalls,\n stranded,\n },\n { status: 200 },\n )\n }\n\n // Per-version kill switch (AGL-1085). Until now a reviewer's only way to\n // stop live bytes was a listing-wide takedown, which also revokes the\n // approved version customers are happily running and hides the listing.\n // Rejection deliberately stays a verdict rather than a kill: most\n // rejections are a thin README, and an unannounced site outage is worse\n // than the gap. This is the deliberate, adjacent action.\n //\n // This does NOT strip the Verified badge, unlike a takedown (AGL-1121).\n // The two claims are scoped differently and the split is the whole point:\n // Verified says a human vouched for the PUBLISHER and survives version\n // bumps, while the separate \"Reviewed\" chip speaks for THESE bytes and is\n // re-earned per version. Stripping the publisher claim for one bad release\n // would punish an honest mistake, and is not reversible without a full\n // re-review. A takedown is the action that contradicts the publisher claim,\n // and that one does strip it.\n //\n // That reasoning only holds because the BYTES claim is withdrawn instead —\n // which it now is, below. It was not before, and the gap is what made\n // keeping the badge unsafe rather than merely debatable.\n if (action === 'revoke-version' || action === 'unrevoke-version') {\n const version = String(body?.version ?? '')\n if (!listingId || !version) {\n return Response.json(\n { error: 'Listing and version required' },\n { status: 400 },\n )\n }\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const listing = (await listingRef.get()).data() ?? {}\n const revocationRef = firestore.collection('revocations').doc(listingId)\n const current = (await revocationRef.get()).data() as\n | PluginRevocation\n | undefined\n const revoking = action === 'revoke-version'\n const next = nextRevocationState(current, {\n type: revoking ? 'revoke-version' : 'unrevoke-version',\n version,\n })\n if (next) {\n await revocationRef.set(\n {\n ...next,\n reason: String(body?.reason ?? current?.reason ?? '').slice(0, 500),\n revokedBy: decoded.uid,\n revokedAt: FieldValue.serverTimestamp(),\n },\n { merge: true },\n )\n } else {\n await revocationRef.delete()\n }\n // Same reach as the takedown path above (AGL-1152): a per-version\n // revocation changes what every cached page renders, and nothing else\n // drops that HTML.\n await dropCachesForListing(firestore, listingId)\n\n // Withdraw the \"Reviewed\" chip when the bytes we just killed are the ones\n // customers are being offered (AGL-1121).\n //\n // This was ASSUMED to happen already and did not. `latestVersionReviewState`\n // is written only by approve/reject and on publish, so a version approved\n // and later revoked kept `'approved'` — and since a per-version revocation\n // deliberately does NOT hide the listing (that is the whole difference from\n // a takedown), the marketplace went on showing \"A human at Aglyn read these\n // exact bytes\" about bytes we had just stopped from executing. Revocation\n // is not surfaced anywhere else in the browse or listing UI either, so\n // nothing contradicted it.\n //\n // `revoked` rather than `rejected`: it was not turned down in review, it\n // was killed afterwards, and the audit trail should not blur those. Both\n // consumers test against `'approved'`, so this correctly drops the chip and\n // raises the caution alert.\n //\n // Only when it is the LATEST version, because that is what both consumers\n // describe. Revoking an old version says nothing about what is on offer.\n const isLatest = revocationWithdrawsReviewedClaim({\n revokedVersion: version,\n latestVersion: String(listing['latestVersion'] ?? ''),\n })\n if (isLatest) {\n const versionSnapshot = await listingRef\n .collection('pluginVersions')\n .doc(version)\n .get()\n await listingRef.set(\n {\n latestVersionReviewState: revoking\n ? REVOKED_VERSION_REVIEW_STATE\n : // Restoring returns it to whatever the version's own verdict\n // says, rather than assuming `approved` — un-revoking a version\n // that was never approved must not promote it.\n String(versionSnapshot.get('reviewState') ?? 'pending'),\n },\n { merge: true },\n )\n }\n\n // The offer follows the kill switch (AGL-2306). A revoked version is\n // refused by `install-plugin`, so leaving it as `latestApprovedVersion`\n // advertises an update that cannot be taken; un-revoking restores it.\n // Both directions, because both change what is installable.\n await repairLatestApprovedVersion(listingRef, next)\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.revocation.${revoking ? 'revoke' : 'restore'}`,\n target: `marketplaceListings/${listingId}/pluginVersions/${version}`,\n after: {\n versions: next?.versions ?? null,\n ...(isLatest ? { latestVersionReviewStateChanged: true } : {}),\n },\n at: FieldValue.serverTimestamp(),\n })\n\n if (listing.profileId) {\n await notifyOrgAdmins(String(listing.profileId), {\n type: 'marketplace.review',\n title: revoking\n ? `\"${listing.displayName}\" v${version} was stopped`\n : `\"${listing.displayName}\" v${version} was allowed to run again`,\n body: revoking\n ? 'It has been disabled on every site running it. Sites showing ' +\n 'this plugin now render a placeholder.'\n : 'Sites running it are no longer blocked.',\n orgId: String(listing.profileId),\n link: '/',\n }).catch(() => undefined)\n }\n\n return Response.json(\n { ok: true, version, revoked: revoking },\n { status: 200 },\n )\n }\n\n // Declining a verification request (AGL-1217). Handled before the ACTIONS\n // lookup because it deliberately has NO `reviewStatus` to move to: the\n // listing stays exactly as live as it was. Refusing a badge is not a\n // verdict on the code, and routing it through the status ladder would\n // make it one.\n if (action === 'decline-verification') {\n const declineReason = String(body?.reason ?? '').trim().slice(0, 500)\n if (!listingId) {\n return Response.json({ error: 'Unknown action' }, { status: 400 })\n }\n // Required, unlike most fields here. The publisher is notified of this\n // and then has to wait out a cooldown before asking again; \"no, and we\n // will not say why, try in a month\" is not a usable answer.\n if (!declineReason) {\n return Response.json(\n { error: 'A reason is required — the publisher is told it' },\n { status: 400 },\n )\n }\n const listingRef = firestore\n .collection('marketplaceListings')\n .doc(listingId)\n const listing = (await listingRef.get()).data()\n if (!listing) {\n return Response.json({ error: 'Unknown listing' }, { status: 404 })\n }\n if (listing.verificationRequest?.state !== 'pending') {\n return Response.json(\n { error: 'No verification request is waiting' },\n { status: 409 },\n )\n }\n await listingRef.set(\n {\n verificationRequest: {\n ...listing.verificationRequest,\n state: 'declined',\n decidedAt: FieldValue.serverTimestamp(),\n decidedBy: decoded.uid,\n declineReason,\n },\n },\n { merge: true },\n )\n /*\n * THE AUDIT ROW THIS BRANCH NEVER WROTE (AGL-2328).\n *\n * Every sibling branch in this file audits, and the file header at the\n * top claims the route is audited. This one mutated\n * `verificationRequest.state`, notified the publisher and started a\n * cooldown, and left no record — so a decline was the one staff\n * decision here that could not be reviewed afterwards, on the action\n * whose reason staff are REQUIRED to type.\n *\n * `reason` uses the audit log's own reason column rather than being\n * buried in `after`, because the audit page renders and exports that\n * column and searches it (AGL-1652) — a why nobody can filter on is a\n * why nobody reads.\n */\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n actorEmail: decoded.email ? String(decoded.email) : null,\n action: 'plugins.verification.decline',\n scope: 'marketplace',\n target: `marketplaceListings/${listingId}`,\n before: { verificationState: 'pending' },\n after: {\n verificationState: 'declined',\n cooldownDays: VERIFICATION_DECLINE_COOLDOWN_DAYS,\n },\n reason: declineReason,\n at: FieldValue.serverTimestamp(),\n })\n\n const publisherOrgId = String(listing.profileId ?? '')\n if (publisherOrgId) {\n await notifyOrgAdmins(publisherOrgId, {\n type: 'marketplace.review',\n title: `Verification declined for \"${listing.displayName}\"`,\n // Says plainly that nothing about the listing changed. Without it a\n // publisher reads \"declined\" as a takedown of the plugin itself.\n body:\n `${declineReason}\\n\\nYour plugin is unaffected and stays listed. ` +\n `You can request verification again in ` +\n `${VERIFICATION_DECLINE_COOLDOWN_DAYS} days.`,\n orgId: publisherOrgId,\n link: '/',\n }).catch(() => undefined)\n }\n return Response.json({ ok: true, state: 'declined' }, { status: 200 })\n }\n\n const nextStatus = ACTIONS[action]\n if (!listingId || !nextStatus) {\n return Response.json({ error: 'Unknown action' }, { status: 400 })\n }\n const reason = String(body?.reason ?? '').slice(0, 500)\n const category = String(body?.category ?? '')\n if (action === 'reject') {\n const invalid = rejectionInputError(category, reason)\n if (invalid) return Response.json({ error: invalid }, { status: 400 })\n }\n\n const listingRef = firestore.collection('marketplaceListings').doc(listingId)\n const listing = (await listingRef.get()).data()\n if (!listing) return Response.json({ error: 'Unknown listing' }, { status: 404 })\n\n // Both gates that expose a plugin to customers require a completed\n // checklist (AGL-963).\n //\n // `list` matters MORE than `verify`, which is easy to get backwards:\n // listing is what makes `isListingBrowsable` true, so it is the moment\n // executable third-party code becomes installable by every workspace.\n // `verify` only adds the badge on top. Gating the badge while leaving\n // listing open would put the ceremony on the weaker action.\n //\n // `start-review` and `reject` stay ungated on purpose: a reviewer must\n // be able to throw something out without first ticking eight boxes\n // about a bundle they have already decided against.\n if (action === 'verify' || action === 'list') {\n const version = String(listing.latestVersion ?? '')\n const versionSnapshot = await listingRef\n .collection('pluginVersions')\n .doc(version)\n .get()\n const outstanding = outstandingChecklistItems(\n versionSnapshot.get('reviewChecklist'),\n String(versionSnapshot.get('sha256') ?? ''),\n )\n if (outstanding.length) {\n return Response.json(\n {\n error: `Review checklist incomplete — ${outstanding.length} required item(s) outstanding`,\n outstanding,\n },\n { status: 409 },\n )\n }\n }\n\n await listingRef.set(\n {\n reviewStatus: nextStatus,\n reviewedBy: decoded.uid,\n reviewedAt: FieldValue.serverTimestamp(),\n // Granting the badge answers any request that was waiting (AGL-1217).\n // Left alone it would sit `pending` forever, so the staff queue would\n // keep offering a decision on a listing that already has the badge,\n // and the publisher's button would stay disabled as \"already pending\"\n // with nothing to wait for.\n //\n // Only when something is actually waiting: a `verify` on a listing\n // nobody asked about must not invent a request that was never made.\n ...(action === 'verify' &&\n listing.verificationRequest?.state === 'pending'\n ? {\n verificationRequest: {\n ...listing.verificationRequest,\n state: 'granted',\n decidedAt: FieldValue.serverTimestamp(),\n decidedBy: decoded.uid,\n },\n }\n : {}),\n ...(action === 'reject'\n ? { rejectionReason: reason, rejectionCategory: category }\n : {\n rejectionReason: FieldValue.delete(),\n rejectionCategory: FieldValue.delete(),\n }),\n },\n { merge: true },\n )\n\n // Tell the publisher their listing moved (rejections especially).\n if (\n listing.profileId &&\n ['reject', 'list', 'verify', 'delist'].includes(action)\n ) {\n // Publishers are ORGS now (AGL-652), so `profileId` is an org id —\n // writing to users/{profileId}/notifications silently dropped every\n // verdict into a user document nobody reads. Notify the org's managers.\n const publisherOrgId = String(listing.profileId ?? '')\n const publisherSlug = publisherOrgId\n ? ((\n await firestore.collection('orgs').doc(publisherOrgId).get()\n ).get('slug') as string | undefined)\n : undefined\n if (publisherOrgId) {\n await notifyOrgAdmins(publisherOrgId, {\n type: 'marketplace.review',\n title:\n action === 'reject'\n ? `\"${listing.displayName}\" was rejected`\n : action === 'delist'\n ? `\"${listing.displayName}\" is back in review`\n : `\"${listing.displayName}\" is now ${nextStatus}`,\n body:\n action === 'reject'\n ? // Category, then what to do about it, then the reviewer's own\n // words (AGL-977). The publisher's first question is \"what do\n // I fix\" — a bare comment answered that only as well as the\n // reviewer happened to write it.\n [\n pluginRejectionCategory(category)?.label,\n pluginRejectionCategory(category)?.guidance,\n reason,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n : action === 'delist'\n ? reason ||\n 'It has been removed from the marketplace while we take ' +\n 'another look. Existing installs keep working.'\n : 'Your plugin passed review.',\n orgId: publisherOrgId,\n link: publisherSlug\n ? buildRoute(Route.ORG_MARKETPLACE, {\n orgSlug: publisherSlug,\n })\n : '/',\n }).catch(() => undefined)\n await emailPublisher(\n publisherOrgId,\n action === 'reject'\n ? `${listing.displayName} was rejected — ${rejectionHeadline(\n category,\n reason,\n )}`\n : action === 'delist'\n ? `${listing.displayName} was removed from the marketplace`\n : `${listing.displayName} is now ${nextStatus}`,\n action === 'reject' || action === 'delist'\n ? reason ||\n 'It has been removed from the marketplace while we take ' +\n 'another look. Existing installs keep working.'\n : 'Your plugin passed review and is live in the marketplace.',\n )\n }\n }\n\n await firestore.collection('adminAudit').add({\n actorUid: decoded.uid,\n action: `plugins.review.${action}`,\n target: `marketplaceListings/${listingId}`,\n after: { reviewStatus: nextStatus, ...(reason ? { reason } : {}) },\n at: FieldValue.serverTimestamp(),\n })\n\n return Response.json({ ok: true, reviewStatus: nextStatus }, { status: 200 })\n } catch (error) {\n // An unverifiable credential is a 401, not a fault of ours\n // (AGL-1993). Null for anything else, so a real failure keeps its 500.\n const unauthenticated = invalidIdTokenResponse(error)\n if (unauthenticated) return unauthenticated\n console.error(error)\n return Response.json({ error: 'Review action failed' }, { status: 500 })\n }\n}\n\nexport { handler as marketplaceAdminReviews }\n"],"names":["REVOKED_VERSION_REVIEW_STATE","revocationWithdrawsReviewedClaim","shouldStripVerifiedOnTakedown","VERIFIED_STRIPPED_STATUS","checkPluginBundle","isPluginRevoked","newestInstallableVersion","isStoredVerdictCurrent","nextRevocationState","PLUGIN_HOST_ABI_VERSION","PLUGIN_VERIFIER_VERSION","pluginArtifactPath","pluginRequestFromWeb","readPluginContributions","emailUnverifiedResponse","findUserByUidAcrossPools","firebaseAdmin","isImpersonationSession","updateExisting","invalidIdTokenResponse","buildRoute","compareArtifactVersions","Route","outstandingChecklistItems","PLUGIN_REVIEW_CHECKLIST","pluginRejectionCategory","rejectionHeadline","rejectionInputError","attestationsForBytes","VERIFICATION_DECLINE_COOLDOWN_DAYS","PUBLISHER_AGREEMENT_VERSION","publisherAgreementState","FieldValue","notifyOrgAdmins","emailPublisher","dropCachesForListing","REQUIRED_OR_OPTIONAL","Set","map","item","id","ACTIONS","list","verify","reject","delist","unverify","listingDetail","firestore","listingId","requestedVersion","listing","versions","attestationEntries","acceptance","listingRef","collection","doc","snapshot","get","data","Response","json","error","status","versionsSnapshot","orderBy","limit","docs","publishedAt","version","String","trust","sha256","hostAbi","Number","capabilities","contributes","elements","toDate","toISOString","installCount","activeInstalls","signed","Boolean","repositoryUrl","reviewState","grandfathered","verification","reviewChecklist","publisherAttestation","publisherId","profileId","publisher","publisherProfile","revocation","pendingFirst","reverse","find","entry","reviewVersion","latestVersion","artifactsBucket","process","env","PLUGIN_ARTIFACTS_BUCKET","reviewEntry","reviewSha","stored","storedIsCurrent","verifier","ok","problems","checks","verifierCached","bytes","app","storage","bucket","file","download","result","toString","declaredNetwork","Array","isArray","network","origin","declaredContributions","set","verifierVersion","checkedAt","serverTimestamp","merge","catch","undefined","Object","values","filter","attesterUid","by","attestedAt","at","attestedBy","found","record","email","displayName","description","verificationRequest","state","requestedAt","declineReason","readme","license","categories","homepageUrl","publisherName","publisherSlug","reviewStatus","rejectionReason","rejectionCategory","priceUsd","hidden","hiddenAt","hiddenReason","revoked","revokedVersions","unpublished","deletedAt","private","visibility","platformHostAbi","checklist","fromEntries","entries","checklistOutstanding","attestation","publisherAgreement","acceptedAt","required","repairLatestApprovedVersion","newest","latestApprovedVersion","delete","updatedAt","handler","request","headers","method","body","query","rawHeaders","authorization","idToken","startsWith","slice","length","decoded","auth","verifyIdToken","email_verified","detailId","where","rows","Promise","all","latest","ref","latestReviewState","queue","row","verificationRequests","listedSnapshot","includes","listed","versionDoc","pendingVersions","realmVersions","versionCount","publisherIds","publishers","getAll","exists","action","hideReason","reason","trim","reviewUid","target","targetSnapshot","stripVerified","isListingTarget","hiddenBy","uid","isPlugin","killsInstalledCopies","revocationRef","current","next","type","revokedBy","revokedAt","source","add","actorUid","subjectUid","after","unverified","versionSnapshot","itemId","checked","has","versionRef","listingSnapshot","approving","outstanding","category","invalid","reviewedBy","reviewedAt","reviewedSha256","reviewRejectionReason","reviewRejectionCategory","signature","trustGrantedBy","trustGrantedAt","latestVersionReviewState","previous","liveInstalls","stranded","title","orgId","link","revoking","isLatest","revokedVersion","latestVersionReviewStateChanged","decidedAt","decidedBy","actorEmail","scope","before","verificationState","cooldownDays","publisherOrgId","nextStatus","label","guidance","join","ORG_MARKETPLACE","orgSlug","unauthenticated","console","marketplaceAdminReviews"],"mappings":"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"}
|