@aglyn/plugins-marketplace 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +51 -0
- package/src/index.d.ts +19 -0
- package/src/index.js +20 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/artifact-update-dialog.component.d.ts +27 -0
- package/src/lib/components/artifact-update-dialog.component.js +244 -0
- package/src/lib/components/artifact-update-dialog.component.js.map +1 -0
- package/src/lib/components/host-plugins-card.component.d.ts +23 -0
- package/src/lib/components/host-plugins-card.component.js +566 -0
- package/src/lib/components/host-plugins-card.component.js.map +1 -0
- package/src/lib/components/listing-content.component.d.ts +57 -0
- package/src/lib/components/listing-content.component.js +1880 -0
- package/src/lib/components/listing-content.component.js.map +1 -0
- package/src/lib/components/listing-image.component.d.ts +46 -0
- package/src/lib/components/listing-image.component.js +38 -0
- package/src/lib/components/listing-image.component.js.map +1 -0
- package/src/lib/components/listing-reviews.component.d.ts +22 -0
- package/src/lib/components/listing-reviews.component.js +419 -0
- package/src/lib/components/listing-reviews.component.js.map +1 -0
- package/src/lib/components/marketplace-browse.component.d.ts +38 -0
- package/src/lib/components/marketplace-browse.component.js +802 -0
- package/src/lib/components/marketplace-browse.component.js.map +1 -0
- package/src/lib/components/plugin-site-set-panel.component.d.ts +24 -0
- package/src/lib/components/plugin-site-set-panel.component.js +137 -0
- package/src/lib/components/plugin-site-set-panel.component.js.map +1 -0
- package/src/lib/components/plugin-site-set.component.d.ts +43 -0
- package/src/lib/components/plugin-site-set.component.js +425 -0
- package/src/lib/components/plugin-site-set.component.js.map +1 -0
- package/src/lib/components/rating-input.component.d.ts +3 -0
- package/src/lib/components/rating-input.component.js +47 -0
- package/src/lib/components/rating-input.component.js.map +1 -0
- package/src/lib/components/report-target.component.d.ts +36 -0
- package/src/lib/components/report-target.component.js +181 -0
- package/src/lib/components/report-target.component.js.map +1 -0
- package/src/lib/components/uninstall-impact-dialog.component.d.ts +40 -0
- package/src/lib/components/uninstall-impact-dialog.component.js +244 -0
- package/src/lib/components/uninstall-impact-dialog.component.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +8 -0
- package/src/lib/constants/bundle-common.js +9 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/hooks/use-artifact-update.d.ts +41 -0
- package/src/lib/hooks/use-artifact-update.js +169 -0
- package/src/lib/hooks/use-artifact-update.js.map +1 -0
- package/src/lib/hooks/use-marketplace-actions.d.ts +37 -0
- package/src/lib/hooks/use-marketplace-actions.js +523 -0
- package/src/lib/hooks/use-marketplace-actions.js.map +1 -0
- package/src/lib/model/artifact-merge.d.ts +154 -0
- package/src/lib/model/artifact-merge.js +228 -0
- package/src/lib/model/artifact-merge.js.map +1 -0
- package/src/lib/model/index.d.ts +43 -0
- package/src/lib/model/index.js +41 -0
- package/src/lib/model/index.js.map +1 -0
- package/src/lib/model/marketplace-props.d.ts +57 -0
- package/src/lib/model/marketplace-props.js +441 -0
- package/src/lib/model/marketplace-props.js.map +1 -0
- package/src/lib/model/marketplace.d.ts +833 -0
- package/src/lib/model/marketplace.js +929 -0
- package/src/lib/model/marketplace.js.map +1 -0
- package/src/lib/model/rating-field.d.ts +24 -0
- package/src/lib/model/rating-field.js +33 -0
- package/src/lib/model/rating-field.js.map +1 -0
- package/src/lib/plugin.d.ts +33 -0
- package/src/lib/plugin.js +86 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/billing-webhook.d.ts +25 -0
- package/src/lib/server/billing-webhook.js +1062 -0
- package/src/lib/server/billing-webhook.js.map +1 -0
- package/src/lib/server/checkout.d.ts +76 -0
- package/src/lib/server/checkout.js +477 -0
- package/src/lib/server/checkout.js.map +1 -0
- package/src/lib/server/connect.d.ts +24 -0
- package/src/lib/server/connect.js +205 -0
- package/src/lib/server/connect.js.map +1 -0
- package/src/lib/server/install-dataset-schema.d.ts +32 -0
- package/src/lib/server/install-dataset-schema.js +255 -0
- package/src/lib/server/install-dataset-schema.js.map +1 -0
- package/src/lib/server/install-email-starter.d.ts +65 -0
- package/src/lib/server/install-email-starter.js +279 -0
- package/src/lib/server/install-email-starter.js.map +1 -0
- package/src/lib/server/install-email-template.d.ts +34 -0
- package/src/lib/server/install-email-template.js +252 -0
- package/src/lib/server/install-email-template.js.map +1 -0
- package/src/lib/server/install-layout.d.ts +29 -0
- package/src/lib/server/install-layout.js +323 -0
- package/src/lib/server/install-layout.js.map +1 -0
- package/src/lib/server/install-pin-counts.d.ts +173 -0
- package/src/lib/server/install-pin-counts.js +248 -0
- package/src/lib/server/install-pin-counts.js.map +1 -0
- package/src/lib/server/install-plugin.d.ts +18 -0
- package/src/lib/server/install-plugin.js +405 -0
- package/src/lib/server/install-plugin.js.map +1 -0
- package/src/lib/server/install-template.d.ts +37 -0
- package/src/lib/server/install-template.js +348 -0
- package/src/lib/server/install-template.js.map +1 -0
- package/src/lib/server/install-theme.d.ts +42 -0
- package/src/lib/server/install-theme.js +313 -0
- package/src/lib/server/install-theme.js.map +1 -0
- package/src/lib/server/install.d.ts +27 -0
- package/src/lib/server/install.js +276 -0
- package/src/lib/server/install.js.map +1 -0
- package/src/lib/server/listing-versions.d.ts +26 -0
- package/src/lib/server/listing-versions.js +378 -0
- package/src/lib/server/listing-versions.js.map +1 -0
- package/src/lib/server/preview-image.d.ts +37 -0
- package/src/lib/server/preview-image.js +216 -0
- package/src/lib/server/preview-image.js.map +1 -0
- package/src/lib/server/provenance.d.ts +100 -0
- package/src/lib/server/provenance.js +118 -0
- package/src/lib/server/provenance.js.map +1 -0
- package/src/lib/server/publish-dataset-schema.d.ts +31 -0
- package/src/lib/server/publish-dataset-schema.js +202 -0
- package/src/lib/server/publish-dataset-schema.js.map +1 -0
- package/src/lib/server/publish-email-starter.d.ts +44 -0
- package/src/lib/server/publish-email-starter.js +231 -0
- package/src/lib/server/publish-email-starter.js.map +1 -0
- package/src/lib/server/publish-email-template.d.ts +33 -0
- package/src/lib/server/publish-email-template.js +211 -0
- package/src/lib/server/publish-email-template.js.map +1 -0
- package/src/lib/server/publish-layout.d.ts +33 -0
- package/src/lib/server/publish-layout.js +243 -0
- package/src/lib/server/publish-layout.js.map +1 -0
- package/src/lib/server/publish-plugin.d.ts +18 -0
- package/src/lib/server/publish-plugin.js +485 -0
- package/src/lib/server/publish-plugin.js.map +1 -0
- package/src/lib/server/publish-preconditions.d.ts +86 -0
- package/src/lib/server/publish-preconditions.js +160 -0
- package/src/lib/server/publish-preconditions.js.map +1 -0
- package/src/lib/server/publish-template.d.ts +27 -0
- package/src/lib/server/publish-template.js +215 -0
- package/src/lib/server/publish-template.js.map +1 -0
- package/src/lib/server/publish-theme.d.ts +38 -0
- package/src/lib/server/publish-theme.js +186 -0
- package/src/lib/server/publish-theme.js.map +1 -0
- package/src/lib/server/publish.d.ts +26 -0
- package/src/lib/server/publish.js +204 -0
- package/src/lib/server/publish.js.map +1 -0
- package/src/lib/server/publisher-profile-save.d.ts +30 -0
- package/src/lib/server/publisher-profile-save.js +226 -0
- package/src/lib/server/publisher-profile-save.js.map +1 -0
- package/src/lib/server/publisher-profile.d.ts +86 -0
- package/src/lib/server/publisher-profile.js +116 -0
- package/src/lib/server/publisher-profile.js.map +1 -0
- package/src/lib/server/purchase-entitlement.d.ts +83 -0
- package/src/lib/server/purchase-entitlement.js +118 -0
- package/src/lib/server/purchase-entitlement.js.map +1 -0
- package/src/lib/server/report.d.ts +32 -0
- package/src/lib/server/report.js +101 -0
- package/src/lib/server/report.js.map +1 -0
- package/src/lib/server/reviews.d.ts +41 -0
- package/src/lib/server/reviews.js +240 -0
- package/src/lib/server/reviews.js.map +1 -0
- package/src/lib/server/update-artifact.d.ts +19 -0
- package/src/lib/server/update-artifact.js +569 -0
- package/src/lib/server/update-artifact.js.map +1 -0
- package/src/lib/server/verification-request.d.ts +31 -0
- package/src/lib/server/verification-request.js +173 -0
- package/src/lib/server/verification-request.js.map +1 -0
- package/src/lib/server/version-stats.d.ts +202 -0
- package/src/lib/server/version-stats.js +305 -0
- package/src/lib/server/version-stats.js.map +1 -0
- package/src/lib/server.d.ts +30 -0
- package/src/lib/server.js +95 -0
- package/src/lib/server.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/listing-content.component.tsx"],"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'use client'\n\nimport {\n LISTING_README_MAX_CHARS,\n listingArtifactType,\n installsUnreviewedFallback,\n listingArtifactLabel,\n listingInclusions,\n hasLivePurchaseOf,\n hasOrgLicenceOf,\n licensedOrgIdsFor,\n installTargetsFor,\n isListingDeleted,\n isPrivateListing,\n resolveInstallPlan,\n resolveOrgInstallSummary,\n resolvePluginInstallState,\n resolveUninstallTargets,\n safePublisherHref,\n type InstallTargeting,\n type UninstallTarget,\n} from '../model/marketplace'\nimport UninstallImpactDialog from './uninstall-impact-dialog.component'\nimport { ListingImage } from './listing-image.component'\nimport {\n buildRoute,\n type MarkdownBlock,\n type MarkdownInline,\n parseMarkdownLite,\n PLATFORM_BRAND_NAME,\n offeredPluginVersion,\n PLUGIN_HOST_ABI_VERSION,\n pluginDocsHelp,\n resolveMarkdownLink,\n resolveMediaSrc,\n resolveUpdateState,\n Route,\n updateStateLabel,\n} from '@aglyn/aglyn'\nimport {\n mdiCheckCircle,\n mdiCheckCircleOutline,\n mdiEmailOutline,\n mdiGithub,\n mdiInformationOutline,\n mdiLifebuoy,\n mdiLinkedin,\n mdiStorefrontOutline,\n mdiTwitter,\n mdiWeb,\n} from '@aglyn/shared-data-mdi'\nimport {\n AppLink,\n CardDisplay,\n Container,\n GridItems,\n MdiIcon,\n} from '@aglyn/shared-ui-jsx'\nimport { NextPageTitle } from '@aglyn/shared-ui-next/contexts/next-page-title-provider'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Alert,\n Avatar,\n Box,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n FormControl,\n FormControlLabel,\n FormGroup,\n FormHelperText,\n FormLabel,\n IconButton,\n Link as MuiLink,\n Rating,\n Stack,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n documentId,\n getDoc,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport { useEffect, useMemo, useState } from 'react'\nimport {\n useConsoleHostRoute,\n useFirestore,\n useFirestoreCollection,\n useFirestoreDoc,\n useHostOrgId,\n useUser,\n useScopeTokens,\n} from '@aglyn/tenant-feature-instance'\n/*\n * The MODULE, not the barrel, for the two PURE helpers — the specs that render\n * this page mock `@aglyn/tenant-feature-instance` wholesale to stage their\n * Firestore hooks, and a query builder imported through that barrel disappears\n * under the mock. Neither of these is a hook.\n */\nimport {\n ceilingedWindow,\n collectionCeiling,\n} from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport ListingReviews from './listing-reviews.component'\nimport ReportTarget from './report-target.component'\nimport PluginSiteSet from './plugin-site-set.component'\nimport { MenuItem, TextField } from '@mui/material'\nimport { useMarketplaceActions } from '../hooks/use-marketplace-actions'\nimport { useArtifactUpdate } from '../hooks/use-artifact-update'\nimport ArtifactUpdateDialog from './artifact-update-dialog.component'\n\n/**\n * How many of the site's components the page reads to answer one question.\n *\n * A LOOKUP ceiling, not a list: nothing here renders these documents. It only\n * has to be wide enough that a component install of this listing is inside it.\n */\nconst COMPONENT_LOOKUP_CEILING = 100\n\n/**\n * How many of the buyer's purchase documents the page reads.\n *\n * Wider than the other lookups on purpose — see the query, which explains what\n * a miss costs on the one panel that offers to take money.\n */\nconst PURCHASE_LOOKUP_CEILING = 200\n\n/**\n * How many installs OF THIS LISTING the page reads per artifact type.\n *\n * Narrow because the query already is: both reads carry the listing id, so\n * this bounds \"how many times one workspace installed one thing\" rather than a\n * collection.\n */\nconst ARTIFACT_INSTALL_CEILING = 20\n\ninterface ListingVersionEntry {\n version: string\n changelog?: string\n trust?: string\n hostAbi?: number\n publishedAtMs: number | null\n /** Installs that ever landed on this version (AGL-1036). */\n installCount?: number\n /** Installs on it right now — the \"who is still on v1\" number. */\n activeInstalls?: number\n}\n\n/**\n * The listing totals, reconciled server-side (AGL-1418).\n *\n * Read from the versions route rather than off the listing document, because\n * the listing document holds a SECOND copy of these two numbers that drifted\n * from the per-version ones — which is how the header came to advertise\n * `7 installs · 2 active` above a version history totalling `3 · 1`. One\n * arithmetic, one source, for every card on the page.\n */\ninterface ListingInstallTotals {\n installCount: number\n activeInstalls: number\n /** Installs no version claims, so the per-version split is incomplete. */\n untrackedActiveInstalls: number\n /**\n * The same shortfall all-time (AGL-2339). Served by both branches of\n * `listing-versions.ts` since AGL-1418 and typed by nothing until now,\n * which is why only its `activeInstalls` sibling ever reached the page.\n *\n * Always the LARGER of the two: an uninstall deletes its pin and leaves the\n * all-time accumulator alone.\n */\n untrackedInstallCount: number\n}\n\nconst renderInlines = (inlines: MarkdownInline[]) =>\n inlines.map((inline, index) => {\n switch (inline.type) {\n case 'bold':\n return <strong key={index}>{inline.text}</strong>\n case 'italic':\n return <em key={index}>{inline.text}</em>\n case 'link': {\n /*\n No routing map is passed, and that is the answer rather than an\n omission (AGL-3118). A link REFERENCE names a screen, listing, entry\n or feed of the SITE a document was written for; a listing README is\n read in the console, which serves none of them, so a reference here\n resolves to nothing and renders as its words — never as an anchor\n holding `entry:…`.\n */\n const link = resolveMarkdownLink(inline.href)\n if (!('href' in link)) return <span key={index}>{inline.text}</span>\n return (\n <MuiLink\n key={index}\n href={link.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n color=\"primary\"\n underline=\"hover\"\n >\n {inline.text}\n </MuiLink>\n )\n }\n default:\n return <span key={index}>{inline.text}</span>\n }\n })\n\n/**\n * Publisher README (AGL-431), rendered through markdown-lite — the parser\n * only ever emits text/bold/italic/http(s)-links/images, so publisher-\n * written docs can't inject markup or javascript: URLs. Code blocks and\n * tables carry text only (AGL-974); the same guarantee holds for both.\n */\n/**\n * What changed between versions (AGL-976).\n *\n * The changelog was already collected per version and already returned by the\n * versions endpoint, but the only place it appeared was a caption in the\n * sidebar timeline — plain text, in a narrow column, next to a date. A buyer\n * deciding whether to upgrade reads this, and publishers write it as ordinary\n * markdown: a config note, a list of fixes, sometimes a fenced snippet.\n *\n * So it renders through the same markdown-lite path as the README, which\n * gained code fences and tables in AGL-974 — and inherits the same safety\n * posture: no raw HTML, `safeUrl` gating every link.\n *\n * APPROVED VERSIONS ONLY, and that is enforced server-side rather than here\n * (AGL-976). A filter in the renderer would leave the same data leaking\n * through the endpoint to anything else that reads it.\n */\nfunction ListingChangelog({\n versions,\n}: {\n versions: readonly ListingVersionEntry[]\n}) {\n const entries = useMemo(\n () => versions.filter((entry) => String(entry.changelog ?? '').trim()),\n [versions],\n )\n // Nothing to say is different from nothing to show: a listing whose\n // publisher has never written a changelog should not get an empty card\n // implying they withheld one.\n if (!entries.length) return null\n return (\n <CardDisplay\n header={'Changelog'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#versioning--updates',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2.5}>\n {entries.map((entry, index) => (\n <Stack key={entry.version} spacing={1}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n <Typography variant=\"subtitle2\">{`v${entry.version}`}</Typography>\n {index === 0 ? <Chip size=\"small\" label=\"Latest\" /> : null}\n {entry.trust === 'realm' ? (\n <Chip size=\"small\" color=\"success\" label=\"Realm-trusted\" />\n ) : null}\n {entry.publishedAtMs ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {new Date(entry.publishedAtMs).toLocaleDateString()}\n </Typography>\n ) : null}\n </Stack>\n <ListingReadme readme={String(entry.changelog ?? '')} />\n {index < entries.length - 1 ? <Divider /> : null}\n </Stack>\n ))}\n </Stack>\n </CardDisplay>\n )\n}\n\n// Exported for the renderer-parity spec (AGL-1315).\nexport function ListingReadme({ readme }: { readme: string }) {\n const blocks = useMemo<MarkdownBlock[]>(\n () => parseMarkdownLite(readme.slice(0, LISTING_README_MAX_CHARS)),\n [readme],\n )\n return (\n <Stack spacing={1.5}>\n {blocks.map((block, index) => {\n switch (block.type) {\n case 'heading':\n return (\n <Typography\n key={index}\n variant={block.level === 2 ? 'h6' : 'subtitle1'}\n >\n {renderInlines(block.inlines)}\n </Typography>\n )\n case 'image':\n return (\n <Box\n key={index}\n component=\"img\"\n // Resolved like `ListingImage` next door (AGL-1686). No\n // `hostId`: a listing belongs to a publishing ORG, not to a\n // site, so the scope the picker baked in is already the right\n // one and there is no rendering host to re-point it at.\n src={resolveMediaSrc(block.src)}\n alt={block.alt}\n loading=\"lazy\"\n sx={{\n maxWidth: '100%',\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n }}\n />\n )\n case 'list':\n return (\n <Stack key={index} component=\"ul\" spacing={0.5} sx={{ my: 0 }}>\n {block.items.map((item, itemIndex) => (\n <Typography key={itemIndex} component=\"li\" variant=\"body2\">\n {renderInlines(item)}\n </Typography>\n ))}\n </Stack>\n )\n // A README's install steps (AGL-1320) — a real `<ol>` carrying\n // `start`, so step 4 of a continued run still reads as step 4.\n case 'orderedList':\n return (\n <Stack\n key={index}\n component=\"ol\"\n start={block.start}\n spacing={0.5}\n sx={{ my: 0 }}\n >\n {block.items.map((item, itemIndex) => (\n <Typography key={itemIndex} component=\"li\" variant=\"body2\">\n {renderInlines(item)}\n </Typography>\n ))}\n </Stack>\n )\n // A README's example snippet (AGL-974). Scrolls rather than wraps —\n // a wrapped command line reads as two commands.\n case 'code':\n return (\n <Box\n key={index}\n component=\"pre\"\n sx={{\n my: 0,\n p: 1.5,\n overflowX: 'auto',\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n bgcolor: 'action.hover',\n typography: 'body2',\n fontFamily: 'monospace',\n }}\n >\n <code>{block.text}</code>\n </Box>\n )\n // The config table (AGL-974) — the block a plugin README is\n // mostly made of. Wrapped in its own scroller so a wide table\n // never pushes the page sideways.\n case 'table':\n return (\n <Box key={index} sx={{ overflowX: 'auto' }}>\n <Box\n component=\"table\"\n sx={{\n borderCollapse: 'collapse',\n width: '100%',\n '& th, & td': {\n border: 1,\n borderColor: 'divider',\n px: 1,\n py: 0.5,\n },\n '& th': { bgcolor: 'action.hover' },\n }}\n >\n <thead>\n <tr>\n {block.header.map((cell, cellIndex) => (\n <Typography\n key={cellIndex}\n component=\"th\"\n variant=\"body2\"\n sx={{\n textAlign: block.align[cellIndex] ?? 'left',\n fontWeight: 600,\n }}\n >\n {renderInlines(cell)}\n </Typography>\n ))}\n </tr>\n </thead>\n <tbody>\n {block.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <Typography\n key={cellIndex}\n component=\"td\"\n variant=\"body2\"\n sx={{ textAlign: block.align[cellIndex] ?? 'left' }}\n >\n {renderInlines(cell)}\n </Typography>\n ))}\n </tr>\n ))}\n </tbody>\n </Box>\n </Box>\n )\n // A README quote (AGL-1315) — the surface's body size, italic\n // behind a left accent in the theme's divider tone.\n case 'quote':\n return (\n <Typography\n key={index}\n component=\"blockquote\"\n variant=\"body2\"\n sx={{\n my: 0,\n mx: 0,\n pl: 1.5,\n borderLeft: 3,\n borderColor: 'divider',\n fontStyle: 'italic',\n color: 'text.secondary',\n }}\n >\n {renderInlines(block.inlines)}\n </Typography>\n )\n default:\n return (\n <Typography key={index} variant=\"body2\">\n {renderInlines(block.inlines)}\n </Typography>\n )\n }\n })}\n </Stack>\n )\n}\n\n/**\n * Whether the detail page has nothing to show, so the zero state stands in\n * for the listing (AGL-998).\n *\n * Existence is `$id`, which `useFirestoreDoc`'s `idField` stamps on every\n * snapshot that exists and on none that does not. A listing FIELD cannot\n * answer this question: browse asks nothing about a publisher, so gating on\n * `profileId` takes a listing the grid is happily showing and 404s it the\n * moment someone opens it (AGL-2700). Deletion is the shared predicate, for\n * the reason its own docblock gives.\n *\n * `!== 'loading'` and not `=== 'success'` (AGL-1066): a refused read reaches\n * 'error', and a listing page rendered over `undefined` is worse than the\n * zero state this exists to show.\n */\nexport function listingIsMissing(\n listing: { $id?: string; deletedAt?: unknown } | undefined,\n status: 'loading' | 'success' | 'error',\n): boolean {\n if (status === 'loading') return false\n return !listing?.$id || isListingDeleted(listing)\n}\n\nexport interface MarketplaceListingContentProps {\n hostId: string\n listingId: string\n /** Org-role permissions resolved by the shell (install gating). */\n permissions: Record<string, boolean | undefined>\n /**\n * Rendered under the org-scope `/marketplace` route (AGL-772) rather than\n * a site's marketplace tab. The publisher page has no org route yet, so the\n * publisher renders as text at org scope instead of linking to a per-site\n * page being retired.\n */\n orgScoped?: boolean\n /**\n * The acting org's slug from the URL (AGL-869). At org scope the publisher\n * link builds from it directly rather than the async host resolution.\n */\n orgSlug?: string\n /**\n * The org's sites, for the install-targeting picker (AGL-773). Present only\n * at org scope; when given (and non-empty) the CTA offers All sites vs\n * Selected sites instead of the single org/host choice.\n */\n hosts?: ReadonlyArray<{ id: string; label: string }>\n}\n\n/**\n * Marketplace listing detail (AGL-95/419), relocated from the app route —\n * the app keeps the Dashboard chrome and renders this through the\n * 'marketplaceListing' widget slot. Full description, preview image,\n * version history, publisher block, and the install/buy CTA.\n */\nexport function MarketplaceListingContent({\n hostId,\n listingId,\n permissions,\n orgScoped,\n orgSlug: orgSlugProp,\n hosts,\n}: MarketplaceListingContentProps) {\n // The publisher link was `/{hostDocId}/marketplace/publisher/{id}` — the\n // pre-AGL-621 shape, dead since. The sibling browse grid was fixed for\n // exactly this (AGL-673) and this file was missed; both now build the\n // route from the shared table (AGL-685).\n const { orgSlug: resolvedOrgSlug, subdomain } = useConsoleHostRoute(hostId)\n // Prefer the URL slug (AGL-869): synchronous and always present at org scope.\n const orgSlug = orgSlugProp ?? resolvedOrgSlug\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n // Hoisted above the actions hook (AGL-2331): a purchase licenses an\n // ORGANIZATION, so `buy` has to name the workspace it is buying for rather\n // than let the server infer it from whichever site the surface happens to\n // be acting through.\n const orgId = useHostOrgId(hostId)\n const { install, installPlan, buy, uninstall } = useMarketplaceActions(\n hostId,\n orgId,\n )\n /** The uninstall awaiting its impact check and confirmation (AGL-1027). */\n const [pendingUninstall, setPendingUninstall] = useState<{\n scope: 'org' | 'host'\n targets: UninstallTarget[]\n } | null>(null)\n const [installScope, setInstallScope] = useState<'org' | 'host'>('org')\n // Confirm before writing install pins (AGL-867): the install is deliberate\n // and site-scoped, so it names its targets before committing.\n const [confirmOpen, setConfirmOpen] = useState(false)\n // Updating a COPIED artifact is never a plain re-install (AGL-1018): the\n // copy has been edited in the workspace, so the update is previewed field by\n // field before anything is written.\n const {\n preview: updatePreview,\n loading: updateLoading,\n loadPreview,\n applyUpdate,\n setPreview: setUpdatePreview,\n } = useArtifactUpdate(hostId)\n const [updateOpen, setUpdateOpen] = useState(false)\n // Screenshot lightbox (AGL-869): the clicked screenshot's URL, or null.\n const [lightboxUrl, setLightboxUrl] = useState<string | null>(null)\n // Org-scope install targeting (AGL-773): All sites vs a chosen subset. Only\n // engaged at org scope with a known site list; otherwise the per-site tab's\n // simpler org/host choice (AGL-656) still applies.\n const orgTargeting = Boolean(orgScoped && hosts && hosts.length > 0)\n const [targeting, setTargeting] = useState<InstallTargeting>('all-sites')\n const [selectedHostIds, setSelectedHostIds] = useState<string[]>([])\n const allHostIds = useMemo(() => (hosts ?? []).map((h) => h.id), [hosts])\n // Listings are org-owned (AGL-652) — \"did I publish this\" is an org\n // comparison, resolved from the routing mirror like the browse grid.\n const [viewerOrgId, setViewerOrgId] = useState<string | null>(null)\n useEffect(() => {\n let active = true\n void getDoc(doc(firestore, 'hostIndex', hostId))\n .then((snapshot) => {\n if (active) setViewerOrgId((snapshot.get('orgId') as string) ?? null)\n })\n .catch(() => undefined)\n return () => {\n active = false\n }\n }, [firestore, hostId])\n\n const { data: listing, status } = useFirestoreDoc<any>(\n () => doc(firestore, 'marketplaceListings', listingId || '-missing-'),\n [firestore, listingId],\n { idField: '$id' },\n )\n // Targets this artifact type can actually install to (AGL-656) — only\n // plugins have an org-scoped pin, so only plugins get a choice.\n const installTargets = useMemo(\n () =>\n listing ? installTargetsFor(listing) : (['host'] as readonly string[]),\n [listing],\n )\n const { data: profile } = useFirestoreDoc<any>(\n () => doc(firestore, 'publisherProfiles', listing?.profileId ?? '-anonymous-'),\n [firestore, listing?.profileId],\n { idField: '$id' },\n )\n /*\n * ORDERED AND CEILINGED (AGL-2501). The page folds this into ONE answer —\n * is a component install of THIS listing present — so a bare `limit`, which\n * Firestore answers in document-id order, would let an arbitrary hundred of\n * the site's components decide it. A site past such a window reads as\n * not-installed, and the button below then offers to install it again.\n */\n const { data: installedRead } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'components'),\n COMPONENT_LOOKUP_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: installedDocs, truncated: installedTruncated } = useMemo(\n () => ceilingedWindow<any>(installedRead, COMPONENT_LOOKUP_CEILING),\n [installedRead],\n )\n // Held at null until the uid resolves (AGL-1440): `marketplacePurchases`\n // is buyer/seller-gated and a LIST is evaluated against the QUERY, so the\n // `-anonymous-` sentinel was denied wholesale on every mount and retried\n // on the refusal cadence. A signed-out viewer simply has no purchases.\n /*\n * ORDERED AND CEILINGED, and the ceiling stays wide (AGL-2501).\n *\n * `orderBy(documentId())` costs nothing here: an equality `where` plus\n * `orderBy(__name__)` is served by the automatic single-field index on\n * `buyerUid`, so no composite index stands between this page and a buyer's\n * licences. Ordering on `purchasedAt` would need one, and would also DROP\n * any purchase written without the field.\n *\n * The window is wider than the others because of what a miss costs here.\n * Every other lookup on this page decides a chip; this one decides whether\n * the Buy button appears, so a purchase that falls outside it does not\n * merely under-report state — it offers to sell a licence the buyer already\n * holds. The probe row is what lets the panel say so.\n */\n const { data: purchaseRead } = useFirestoreCollection<any>(\n () =>\n user?.uid\n ? query(\n collection(firestore, 'marketplacePurchases'),\n where('buyerUid', '==', user.uid),\n orderBy(documentId()),\n limit(PURCHASE_LOOKUP_CEILING + 1),\n )\n : null,\n [firestore, user?.uid],\n { idField: '$id' },\n )\n const { rows: purchaseDocs, truncated: purchasesTruncated } = useMemo(\n () => ceilingedWindow<any>(purchaseRead, PURCHASE_LOOKUP_CEILING),\n [purchaseRead],\n )\n const artifactType = listing ? listingArtifactType(listing) : null\n const isPlugin = artifactType === 'plugin'\n // Plugin installs are version PINS, not component snapshots (AGL-656): a\n // host pin lives at `hosts/{h}/installs/{id}`, an org pin at\n // `orgs/{o}/installs/{id}` and applies to every site. Reading only\n // `components` above never sees either, so an installed plugin read as\n // \"not installed\" here; the two pins tell the honest story, host over org.\n // (`orgId` is resolved above, where `buy` needs it.)\n const { data: hostPin } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'installs', listingId || '-missing-'),\n [firestore, hostId, listingId],\n { idField: '$id' },\n )\n // Held at null while `useHostOrgId` is in flight, never `orgs/-pending-`\n // (AGL-1440): installs are member-gated, so the sentinel was a\n // guaranteed-denied listen on every listing view.\n const { data: orgPin } = useFirestoreDoc<any>(\n () =>\n orgId && listingId\n ? doc(firestore, 'orgs', orgId, 'installs', listingId)\n : null,\n [firestore, orgId, listingId],\n { idField: '$id' },\n )\n // Every site's pin, not just the acting one (AGL-997). At org scope the\n // question is \"which of my sites is this on\", and the two subscriptions\n // above can only answer for one arbitrary site. Read as a fan-in rather\n // than a subscription per host: the host count is a prop, so a per-host\n // hook would change the hook count between renders, and a collection-group\n // query would need an index plus a rules audit to read other orgs' pins\n // it must never see. `pinsNonce` re-reads after this page's own writes,\n // which are the only thing that changes these docs while it is open.\n const [sitePins, setSitePins] = useState<Record<string, any>>({})\n const [pinsNonce, setPinsNonce] = useState(0)\n const hostIdsKey = (hosts ?? []).map((host) => host.id).join('|')\n useEffect(() => {\n if (!orgScoped || !listingId || !hosts?.length) return\n let active = true\n void Promise.all(\n hosts.map(async (host) => {\n const snapshot = await getDoc(\n doc(firestore, 'hosts', host.id, 'installs', listingId),\n )\n return [host.id, snapshot.exists() ? snapshot.data() : null] as const\n }),\n )\n .then((entries) => {\n if (active) setSitePins(Object.fromEntries(entries))\n })\n .catch(() => undefined)\n return () => {\n active = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [firestore, listingId, hostIdsKey, orgScoped, pinsNonce])\n // datasetSchema/emailTemplate installs live in neither collection above\n // (AGL-789) — they become an org dataset or a draft email version, each\n // stamped with the listing it came from. Scoped to this listing rather than\n // reading the whole collection, since the detail page only speaks for one.\n // Scoped (AGL-1044): the AGL-1041 rules reject an unfiltered list for a\n // scoped member, so this would error rather than show fewer installs.\n //\n // Wait for the member doc before listing (AGL-1047). `useScopeTokens`\n // reports `orgWide: true` while loading, so without `scopeLoaded` a scoped\n // collaborator's first render computes `needsScope: false` and sends an\n // UNFILTERED list that the AGL-1041 rules deny per document. It recovers\n // on the next render, which is what makes it easy to miss: the page looks\n // right and logs a denial every mount.\n const {\n tokens: scopeTokens,\n orgWide: viewerOrgWide,\n loaded: scopeLoaded,\n } = useScopeTokens(orgId ?? undefined)\n const needsScope = Boolean(orgId) && !viewerOrgWide\n /*\n * ORDERED (AGL-2501). These two are already narrowed to ONE listing, so the\n * twenty is generous rather than tight — but `artifactInstall` below takes\n * the FIRST live row out of whatever comes back, and an unordered `limit` is\n * answered in document-id order, which makes \"the first\" an arbitrary one.\n * On an org holding more than twenty installs of a single listing the window\n * could hold only deleted rows while a live one sat outside it, and the page\n * would offer to install what is already installed.\n *\n * `documentId()` is what the existing composite index on\n * (`source.listingId`, `visibleTo`) already orders by — Firestore appends the\n * document name to every index — so this needs no new one.\n */\n const { data: datasetInstalls } = useFirestoreCollection<any>(\n () =>\n orgId && scopeLoaded\n ? query(\n collection(firestore, 'orgs', orgId, 'datasets'),\n where('source.listingId', '==', listingId || '-missing-'),\n ...(needsScope\n ? [where('visibleTo', 'array-contains-any', scopeTokens)]\n : []),\n orderBy(documentId()),\n limit(ARTIFACT_INSTALL_CEILING),\n )\n : null,\n [firestore, orgId, scopeLoaded, listingId, needsScope, scopeTokens],\n // Same mutable-predicate exposure as the browse datasets query:\n // `visibleTo` is rewritten by every scope edit, and the rule requires the\n // constraint for anyone who is not org-wide (AGL-1196).\n { idField: '$id', confirmDisappearances: true },\n )\n const { data: emailInstalls } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'emailTemplates'),\n where('installedFrom.listingId', '==', listingId || '-missing-'),\n orderBy(documentId()),\n limit(ARTIFACT_INSTALL_CEILING),\n ),\n [firestore, hostId, listingId],\n { idField: '$id' },\n )\n // A theme installs onto the host document itself (AGL-1020) rather than into\n // a collection, so there is no per-listing query to scope — the site either\n // runs this listing's theme or it does not.\n const { data: themeHostDoc } = useFirestoreDoc<any>(\n () => (artifactType === 'theme' ? doc(firestore, 'hosts', hostId) : null),\n [firestore, hostId, artifactType],\n { idField: '$id' },\n )\n const artifactInstall = useMemo(() => {\n if (artifactType === 'datasetSchema') {\n const hit = (datasetInstalls ?? []).find((entry: any) => !entry.deletedAt)\n return hit ? { version: hit.source?.version ?? null } : undefined\n }\n if (artifactType === 'emailTemplate') {\n const hit = (emailInstalls ?? []).find((entry: any) => !entry.deletedAt)\n return hit ? { version: hit.installedFrom?.version ?? null } : undefined\n }\n if (artifactType === 'theme') {\n const stamp = themeHostDoc?.themeInstalledFrom\n return stamp?.listingId === listingId\n ? { version: stamp?.version ?? null }\n : undefined\n }\n return undefined\n }, [artifactType, datasetInstalls, emailInstalls, themeHostDoc, listingId])\n\n /**\n * The kill switch, on the page with the Install button (AGL-2368).\n *\n * One document read for the whole page — the switch is listing-scoped —\n * and public, which is what lets the marketplace loaders and the\n * host-plugins card read it already.\n */\n const { data: revocation } = useFirestoreDoc<any>(\n () =>\n isPlugin && listingId\n ? doc(firestore, 'revocations', listingId)\n : null,\n [firestore, isPlugin, listingId],\n )\n\n /**\n * The version this listing actually offers (AGL-1016, AGL-2368).\n *\n * For a plugin that is the newest INSTALLABLE version, not `latestVersion`\n * and not merely the newest approved one. This page used to compare against\n * `latestVersion`, so publishing v1.1.0 lit up \"Update to v1.1.0\" for every\n * workspace the moment it was uploaded — and the install route then refused\n * it, because AGL-966 only ever hands out reviewed bytes. The badge was\n * advertising what the marketplace would not give you.\n *\n * `latestApprovedVersion` fixed that and left the same defect one state\n * over: approval is a review verdict and revocation does not clear it, so a\n * killed version stayed the offer. This is the page with the Install and\n * Buy buttons on it, so it cross-checks the mirror against the switch\n * rather than trusting a cache two writes behind.\n */\n const offeredVersion = isPlugin\n ? offeredPluginVersion(listing, revocation)\n : listing?.latestVersion\n\n /**\n * The publisher installing their OWN unreviewed bytes (AGL-1083).\n *\n * `install-plugin` deliberately allows it — you cannot test a version you\n * cannot install, and the AGL-969 checklist asks a publisher to confirm\n * they tested these exact bytes on a site they control. But the affordance\n * said nothing, so it read exactly like installing reviewed, signed code.\n *\n * The condition mirrors the route's fallback rather than approximating it:\n * there, `newest ?? fallback` hands over `latestVersion` ONLY when the\n * owner asks and no approved version exists at all. With an approved\n * version present the server serves that one, and this is not an\n * unreviewed install however new the pending one is.\n */\n const unreviewedInstall =\n isPlugin && installsUnreviewedFallback(listing, viewerOrgId, revocation)\n /** What would actually land — the route's fallback, named. */\n const installingVersion = unreviewedInstall\n ? listing?.latestVersion\n : offeredVersion\n\n const pluginState = useMemo(\n () =>\n resolvePluginInstallState(\n offeredVersion,\n isPlugin ? hostPin : null,\n isPlugin ? orgPin : null,\n ),\n [offeredVersion, isPlugin, hostPin, orgPin],\n )\n\n // Public version history + trust tier (AGL-431): the pluginVersions\n // docs are server-only, so the marketplace API exposes the buyer-safe\n // subset (version/changelog/trust/hostAbi/date).\n const [versions, setVersions] = useState<ListingVersionEntry[]>([])\n const [totals, setTotals] = useState<ListingInstallTotals | null>(null)\n useEffect(() => {\n // Every artifact type now, not just plugins (AGL-1036): the route serves\n // the per-version install counts for all of them, and a component's\n // publisher wants \"who is still on v1\" as much as a plugin's does.\n if (!listing || !listingId) return\n let active = true\n void fetch(\n `/api/marketplace/listing-versions?listingId=${encodeURIComponent(listingId)}`,\n )\n .then((response) => (response.ok ? response.json() : { versions: [] }))\n .then((payload) => {\n if (!active) return\n setVersions(payload?.versions ?? [])\n setTotals(\n typeof payload?.activeInstalls === 'number'\n ? {\n installCount: Number(payload.installCount ?? 0),\n activeInstalls: Number(payload.activeInstalls ?? 0),\n untrackedActiveInstalls: Number(\n payload.untrackedActiveInstalls ?? 0,\n ),\n // THIS PROJECTION is where the field died (AGL-2339). The\n // route served it from both branches; the client copied its\n // sibling and not it, so the page could never render what the\n // server had already computed.\n untrackedInstallCount: Number(\n payload.untrackedInstallCount ?? 0,\n ),\n }\n : null,\n )\n })\n .catch(() => undefined)\n return () => {\n active = false\n }\n // Keyed on the listing's id, not its legacy `type` (AGL-864): an\n // artifactType-only plugin has no `type`, so keying on it left the effect\n // stuck at its undefined first value and the versions fetch never fired.\n //\n // `pinsNonce` re-reads after this page's own writes, so the per-version\n // install counts (AGL-1036) are not left showing the tally from before the\n // update the user just pressed.\n }, [listing?.$id, listingId, pinsNonce])\n /**\n * The install numbers this page is allowed to print (AGL-1418).\n *\n * The route's reconciled totals when they have arrived, and the listing\n * document's own copy only until then. That fallback cannot reintroduce the\n * contradiction it replaced: the version history it used to disagree with is\n * fed by the same response, so before it lands there is nothing on screen to\n * disagree with.\n */\n const installTotals = useMemo<ListingInstallTotals | null>(() => {\n if (totals) return totals\n const stored = Number(listing?.activeInstalls ?? Number.NaN)\n if (!Number.isFinite(stored)) return null\n return {\n installCount: Number(listing?.installCount ?? 0),\n activeInstalls: stored,\n // Zero on the fallback, because the listing document holds no split at\n // all — claiming a shortfall it cannot know would be the contradiction\n // this fallback exists to avoid.\n untrackedActiveInstalls: 0,\n untrackedInstallCount: 0,\n }\n }, [totals, listing?.activeInstalls, listing?.installCount])\n const latestEntry = versions[0]\n const realmTrusted = versions.some((entry) => entry.trust === 'realm')\n const abiIncompatible =\n latestEntry?.hostAbi != null &&\n latestEntry.hostAbi !== PLUGIN_HOST_ABI_VERSION\n\n // Component listings still install into `hosts/{h}/components`; plugin\n // state comes from the pins above. `installed` unifies the two so the CTA\n // and the buy gate read the same for either artifact type.\n const componentInstall = useMemo(\n () =>\n (installedDocs ?? []).find(\n (definition: any) =>\n definition?.marketplace?.listingId === listingId &&\n !definition.deletedAt,\n ),\n [installedDocs, listingId],\n )\n // The SERVER's predicate, imported rather than restated (AGL-2158). This\n // used to be `some(p => p.listingId === listingId)` with no refund test,\n // while `hasLivePurchase` — the gate on all eight ways into paid content —\n // treats a purchase carrying `refundedAt` as absent. The one buyer the two\n // must agree about is the refunded one, and they disagreed: the page said\n // \"Purchased\" and hid the buy button, the install routes answered 402, and\n // the buyer could neither install nor buy it again.\n //\n // ORG-SCOPED SINCE AGL-2331. `hasLivePurchaseOf` answers \"did this PERSON\n // buy it\", which is no longer the question either the install routes or the\n // checkout guard ask: a licence belongs to a workspace, so the acting org is\n // what decides whether this page may install. Reading the person's answer\n // here would put the CTA back in the disagreement AGL-2158 closed — an\n // agency owner would see \"Purchased\" in a client workspace that holds no\n // licence, and the install would 402.\n const purchased = useMemo(\n () => hasOrgLicenceOf(purchaseDocs ?? [], listingId, { orgId, uid: user?.uid }),\n [purchaseDocs, listingId, orgId, user?.uid],\n )\n /**\n * The buyer holds a licence for this listing — in some OTHER workspace\n * (AGL-2331).\n *\n * The state that has no honest rendering without it: an agency developer who\n * bought this component for one client opens it in the next client's\n * workspace and sees a plain Buy button, with nothing to distinguish \"you\n * have never bought this\" from \"you own one, it just does not cover the\n * workspace you are standing in\". Both are a purchase — but only one of them\n * is a surprise when the invoice arrives.\n *\n * Reads the buyer's OWN purchase documents, which the rules have always let\n * them read, so this needs no cross-org read to answer.\n */\n const licensedElsewhere = useMemo(\n () =>\n !purchased &&\n hasLivePurchaseOf(purchaseDocs ?? [], listingId) &&\n licensedOrgIdsFor(purchaseDocs ?? [], listingId).some(\n (licensed) => licensed !== orgId,\n ),\n [purchased, purchaseDocs, listingId, orgId],\n )\n\n const missing = listingIsMissing(listing, status)\n // Somewhere to go from the zero state (AGL-998). Same surface split as\n // every other link here: org route at org scope, host route otherwise,\n // and undefined rather than a link to nowhere when the slug is unresolved.\n const marketplaceHref = orgScoped\n ? orgSlug\n ? buildRoute(Route.ORG_MARKETPLACE, { orgSlug })\n : undefined\n : // The per-site marketplace tab is gone (AGL-975 finished retiring it),\n // so both branches now land on the same org-scope page and the\n // subdomain is no longer part of the URL.\n orgSlug\n ? buildRoute(Route.ORG_MARKETPLACE, { orgSlug })\n : undefined\n const installed = isPlugin\n ? pluginState.scope != null\n : Boolean(componentInstall ?? artifactInstall)\n const installedVersion = isPlugin\n ? pluginState.installedVersion\n : (componentInstall?.marketplace?.version ?? artifactInstall?.version)\n const upToDate = isPlugin\n ? installed && !pluginState.updateAvailable\n : componentInstall && installedVersion >= listing?.latestVersion\n /**\n * The same update comparison the Plugins index and the installation page\n * make (AGL-1016), so all three agree on the version pair rather than each\n * re-deriving it. Only rendered when the viewer already has it installed —\n * \"you have v1.0.0 · v1.1.0 available\" is meaningless to a first-time buyer.\n */\n const updateStatus = useMemo(\n () =>\n resolveUpdateState(\n isPlugin\n ? ((hostPin ?? orgPin) as never)\n : // Copied artifacts are found through four different install\n // collections here, each with its own field for the version, so\n // they are normalised to the one shape provenance reads. The\n // `installedFrom` stamp wins when AGL-1015 wrote one.\n ({\n ...(componentInstall?.installedFrom\n ? { installedFrom: componentInstall.installedFrom }\n : {}),\n ...(installedVersion != null && listingId\n ? { listingId, version: installedVersion }\n : {}),\n } as never),\n listing ?? null,\n artifactType,\n // The kill switch (AGL-2368) — this line said \"Update to vX\" for a\n // version the install route refuses, because approval survives it.\n revocation,\n ),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n isPlugin,\n hostPin,\n orgPin,\n componentInstall,\n installedVersion,\n listingId,\n listing,\n artifactType,\n revocation,\n ],\n )\n const priceUsd = Number(listing?.priceUsd ?? 0)\n const mustBuy =\n priceUsd > 0 && !purchased && listing?.profileId !== viewerOrgId && !installed\n // Updating an installed plugin stays at its current scope; a fresh install\n // uses the picker (plugins) or the artifact's only target (everything else).\n const installTargetScope: 'org' | 'host' | undefined =\n isPlugin && installed\n ? (pluginState.scope ?? undefined)\n : installTargets.length > 1\n ? installScope\n : undefined\n // Org-scope targeting (AGL-773): \"Selected sites\" is only offered when the\n // artifact can host-pin (plugins, components, templates, layouts) — an\n // org-only artifact can't target a subset.\n const canSelectSites = installTargets.includes('host')\n const installPlanSteps = useMemo(\n () =>\n listing\n ? resolveInstallPlan(listing, targeting, {\n selectedHostIds,\n allHostIds,\n })\n : [],\n [listing, targeting, selectedHostIds, allHostIds],\n )\n const versionHistory: any[] = Array.isArray(listing?.versionHistory)\n ? [...listing.versionHistory].sort((a, b) => b.version - a.version)\n : []\n\n // Human summary of exactly where this install lands (AGL-867), read from the\n // same targeting the CTA acts on. An org pin covers every site (now and\n // future); host pins are named so \"Selected sites\" can't silently mean\n // something else.\n const installTargetSummary = (): string => {\n if (orgTargeting && !installed) {\n if (\n installPlanSteps.length === 1 &&\n installPlanSteps[0]?.scope === 'org'\n ) {\n return 'the whole organization — every site, including sites added later'\n }\n const names = installPlanSteps\n .filter((step) => step.scope === 'host')\n .map(\n (step) =>\n (hosts ?? []).find((host) => host.id === step.hostId)?.label ??\n step.hostId,\n )\n if (names.length) {\n return `${names.length} site${names.length === 1 ? '' : 's'}: ${names.join(\n ', ',\n )}`\n }\n return 'the selected targets'\n }\n // Org-only artifacts (dataset schema) always land org-wide — including on\n // re-add, where installTargetScope isn't set (AGL-867).\n if (\n installTargetScope === 'org' ||\n (installTargets.length === 1 && installTargets[0] === 'org')\n ) {\n return 'the whole organization — every site'\n }\n return 'this site'\n }\n\n // The org-wide picture (AGL-997): which sites run this, at which version,\n // and which are still free to add. Only meaningful at org scope for a\n // plugin — everything else installs INTO a site and has no pin to survey.\n const orgPluginScope = Boolean(orgTargeting && isPlugin)\n const orgInstall = useMemo(\n () => resolveOrgInstallSummary(hosts ?? [], sitePins, orgPin ?? null),\n [hosts, sitePins, orgPin],\n )\n /** Run a pin write, then re-read every site's pin. */\n const runSiteEdit = async (work: () => Promise<unknown>) => {\n try {\n await work()\n } finally {\n setPinsNonce((current) => current + 1)\n }\n }\n\n /**\n * A copied artifact with a newer version on offer (AGL-1018).\n *\n * The distinction that matters: a plugin takes an update by moving a pointer,\n * but a component, layout or dataset schema was copied in and then EDITED\n * here, so \"Update\" is a merge. It goes through the review dialog, never\n * straight to the install route.\n */\n //\n // Every non-current state, not just `update-available` (AGL-1034): a copy\n // whose versions cannot be ordered, or that reports `ahead`, is still a copy\n // this workspace may have edited, and sending it to the install route would\n // dead-end on the divergence 409 with nothing offering the review it names.\n const copiedUpdatable =\n !isPlugin &&\n installed &&\n // A theme is a copied artifact like a component, just stored as a field on\n // the site rather than as its own document (AGL-1020) — so it takes the\n // same diff-first update path, and must not fall through to the plain\n // install that would overwrite the site's edits.\n Boolean(componentInstall || (artifactType === 'theme' && artifactInstall)) &&\n updateStatus.state !== 'current'\n const openUpdateReview = () => {\n setUpdatePreview(null)\n setUpdateOpen(true)\n if (listingId) void loadPreview(listingId)\n }\n /**\n * \"Install as a new copy\", which means different things per type.\n *\n * Only a component or layout has a link that can be DETACHED, leaving the\n * customised copy in place as an ordinary artifact — the update route does\n * that. For the others a fresh copy is exactly what the ordinary install\n * already produces (another empty dataset, another inactive draft, a replaced\n * template bundle), quota checks included, so it goes there rather than\n * through a second implementation that would drift from it.\n */\n const runCopy = async () => {\n if (artifactType === 'component' || artifactType === 'layout') {\n return void (await runUpdate('copy'))\n }\n setUpdateOpen(false)\n await runSiteEdit(() =>\n install(listing, installTargetScope, { onDiverged: openUpdateReview }),\n )\n }\n const runUpdate = async (\n mode: 'merge' | 'copy',\n takePaths: string[] = [],\n confirmDestructive = false,\n ) => {\n if (!listingId) return\n const done = await applyUpdate(listingId, {\n mode,\n takePaths,\n confirmDestructive,\n })\n // Left open on failure — a destructive schema update comes back asking for\n // the confirmation tick, and closing would hide the question.\n if (done) {\n setUpdateOpen(false)\n // Re-read the install state and the per-version counts this just moved.\n setPinsNonce((current) => current + 1)\n }\n }\n\n // The actual pin write, run only after the confirm dialog (AGL-867).\n const runInstall = () => {\n setConfirmOpen(false)\n // Re-read every site's pin afterwards (AGL-997). The acting host's pin is\n // a live subscription, but the other sites' are a fan-in read — without\n // this the page went straight from \"Install\" to a bare disabled\n // \"Installed\" button, because the panel that explains WHERE it landed\n // had not seen the write yet.\n void runSiteEdit(() =>\n orgTargeting && !installed\n ? installPlan(listing, installPlanSteps)\n : // A refused install because the copy was edited opens the review\n // instead of toasting advice nothing here acts on (AGL-1034).\n install(listing, installTargetScope, {\n onDiverged: openUpdateReview,\n }),\n )\n }\n\n return (\n <>\n <NextPageTitle screen={listing?.displayName ?? 'Marketplace listing'} />\n <Container gutterY maxWidth=\"xl\">\n {/* A designed zero-state, not a loose sentence (AGL-998). It is\n reached by ordinary means — a bookmark to something since\n unpublished, a link from another environment — so it has to\n offer a way out rather than read as a half-rendered page.\n `listingIsMissing` holds off while the read is loading, so this\n never stands in for a page that is merely still arriving. */}\n {missing ? (\n <CardDisplay contentGutterX contentGutterY>\n <Stack\n spacing={1.5}\n sx={{ alignItems: 'center', textAlign: 'center', py: 6 }}\n >\n <MdiIcon\n path={mdiStorefrontOutline.path}\n color=\"disabled\"\n sx={{ fontSize: 48 }}\n />\n <Typography variant=\"h6\">{'This listing isn’t here'}</Typography>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ maxWidth: 440 }}\n >\n {'It may have been unpublished by its publisher, taken ' +\n 'down, or the link may point somewhere that no longer ' +\n 'exists. Anything you already installed from it keeps ' +\n 'working.'}\n </Typography>\n {marketplaceHref ? (\n <AppLink href={marketplaceHref}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n component=\"span\"\n >\n {'Back to the marketplace'}\n </Button>\n </AppLink>\n ) : null}\n </Stack>\n </CardDisplay>\n ) : (\n <GridItems\n spacing={3}\n // Masonry. Source order here is body (8),\n // changelog (8), sidebar (4) — and two eights cannot share a\n // twelve-column row, so the changelog wrapped and dragged the\n // sidebar down with it. `Install`, the point of the page, opened\n // below the fold under a screen of blank space. Masonry places\n // the sidebar in the columns beside the body card where it\n // belongs, and no card can be pushed past the container's edge.\n masonry\n items={[\n {\n size: { xs: 12, md: 8 },\n // No card header (AGL-1000): the page's hero now carries the\n // listing's name, and the only route that renders this\n // widget is the org listing page — the per-site one\n // redirects to it (AGL-775) — so a heading here would just\n // print the same words twice, inches apart.\n children: (\n <CardDisplay contentGutterX contentGutterY>\n <Stack spacing={2}>\n {/* Resolved, never raw (AGL-1424) — the stored value\n may be a `media:` reference. */}\n <ListingImage\n src={listing?.previewImageUrl}\n alt={`${listing?.displayName} preview`}\n sx={{\n width: '100%',\n maxHeight: 360,\n objectFit: 'cover',\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n }}\n />\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n {listing?.logoUrl ? (\n <Box\n component=\"img\"\n src={listing.logoUrl}\n alt={`${listing?.displayName} logo`}\n sx={{\n width: 32,\n height: 32,\n borderRadius: 1,\n objectFit: 'cover',\n }}\n />\n ) : null}\n {/* What kind of thing this is, said plainly and\n first (AGL-864) — a plugin, a site template, a\n layout, etc. Filled so it reads as the primary\n classification, ahead of the softer category\n chips. */}\n {listing ? (\n <Chip\n size=\"small\"\n color=\"primary\"\n label={listingArtifactLabel(listing)}\n />\n ) : null}\n {(listing?.categories ?? []).map((entry: string) => (\n <Chip key={entry} size=\"small\" label={entry} />\n ))}\n {listing?.category &&\n !(listing?.categories ?? []).length ? (\n <Chip size=\"small\" label={listing.category} />\n ) : null}\n {listing?.license ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={listing.license}\n />\n ) : null}\n {isPlugin ? (\n realmTrusted ? (\n <Chip\n size=\"small\"\n color=\"success\"\n label=\"Realm-trusted\"\n />\n ) : (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Sandboxed\"\n />\n )\n ) : null}\n {/* Two claims, shown separately (AGL-1121): who\n wrote it, and whether these bytes were read.\n\n Both name `PLATFORM_BRAND_NAME`, not the viewing\n org's `productName` (AGL-2351): they say who did\n the verifying and the reading, and that is the\n deployment's own review queue — one catalog\n shared by every org. A white-label agency's brand\n here would claim the agency vetted a publisher it\n has never heard of. */}\n {listing?.reviewStatus === 'verified' ? (\n <Tooltip\n title={\n `A human at ${PLATFORM_BRAND_NAME} confirmed ` +\n 'who this ' +\n 'publisher is, and that the listing describes ' +\n 'what the code does. A claim about the ' +\n 'publisher, not this release — it survives a ' +\n 'version bump.'\n }\n >\n <Chip\n size=\"small\"\n color=\"info\"\n label=\"Verified publisher\"\n />\n </Tooltip>\n ) : null}\n {listing?.latestVersionReviewState === 'approved' ? (\n <Tooltip\n title={\n `A human at ${PLATFORM_BRAND_NAME} read these ` +\n 'exact bytes — ' +\n 'the version on offer — against a required ' +\n 'checklist. Re-earned per version. Not a ' +\n 'security guarantee: every plugin runs in the ' +\n 'same sandbox either way.'\n }\n >\n <Chip size=\"small\" color=\"success\" label=\"Reviewed\" />\n </Tooltip>\n ) : null}\n {/* Private listings never reach browse (AGL-993),\n so this page is the only place their state is\n ever shown — say it beside Verified rather than\n letting an approved private plugin read exactly\n like a marketplace one. */}\n {isPrivateListing(listing ?? {}) ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Private\"\n />\n ) : null}\n <Chip\n size=\"small\"\n color={priceUsd > 0 ? 'primary' : 'default'}\n label={priceUsd > 0 ? `$${priceUsd}` : 'Free'}\n />\n {/*\n The rating in the HEADER (AGL-2173), which is\n where the mockup puts it and where a shopper\n decides. The `Rating` widget existed only\n inside the `Ratings & comments` card at the\n bottom of a long page, below the README — past\n the point the install decision is made.\n */}\n {listing?.ratingCount ? (\n <Stack\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center' }}\n >\n <Rating\n size=\"small\"\n readOnly\n precision={0.1}\n value={Number(listing.ratingAverage ?? 0)}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {`${listing.ratingAverage ?? 0} (${listing.ratingCount})`}\n </Typography>\n </Stack>\n ) : null}\n {/* Two numbers that are NOT the same question\n (AGL-1418). They used to read `7 installs · 2\n active` — \"installs\" first and unqualified, so\n the big number was the one nobody can reconcile\n against anything, and it sat two cards above a\n version history saying `3 installs`. Now: the\n live count leads, both are named, and both come\n from the reconciled totals rather than the\n listing document's drifted private copy. */}\n <Tooltip\n title={\n 'Counted once per install, whether it covers a ' +\n 'single site or a whole organization — and ' +\n 'including the publisher’s own. “All time” ' +\n 'counts installs that have since been removed, ' +\n 'so it never falls.'\n }\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {`v${listing?.latestVersion ?? '…'}`}\n {/* Hidden at zero rather than printed as \"0\n active installs\", for the same reason the\n version rows are (AGL-1036): on a listing\n nobody has reached yet it reads as a\n failure. */}\n {installTotals?.installCount ||\n installTotals?.activeInstalls\n ? ` · ${installTotals.activeInstalls} active ` +\n `install${\n installTotals.activeInstalls === 1 ? '' : 's'\n }`\n : ''}\n {installTotals?.installCount\n ? ` · ${installTotals.installCount} all time`\n : ''}\n </Typography>\n </Tooltip>\n </Stack>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {listing?.description ?? 'No description provided.'}\n </Typography>\n {/* Keyed off the BYTES, not the publisher badge\n (AGL-1121). This used to hide whenever the listing\n was `verified` — a status that survives a version\n bump — so the one case that most needed the\n caution, brand-new unreviewed code from a\n previously-verified publisher, was the one case\n that suppressed it. */}\n {isPlugin &&\n !realmTrusted &&\n listing?.latestVersionReviewState !== 'approved' ? (\n <Alert severity=\"info\">\n {'Marketplace plugin: runs sandboxed and cannot ' +\n 'access your site data directly. Review the ' +\n 'publisher and docs before installing.'}\n </Alert>\n ) : null}\n {isPrivateListing(listing ?? {}) ? (\n <Alert severity=\"info\">\n {'Private plugin: it is never listed in the ' +\n 'marketplace, and only your organization’s ' +\n 'sites can install it. It passes the same ' +\n 'review as every other plugin.'}\n </Alert>\n ) : null}\n {abiIncompatible ? (\n <Alert severity=\"warning\">\n {`Built for platform generation ${latestEntry?.hostAbi}; ` +\n `this platform runs ${PLUGIN_HOST_ABI_VERSION}. ` +\n 'It will not load until the publisher ships a ' +\n 'compatible version.'}\n </Alert>\n ) : null}\n {(listing?.screenshots ?? []).length ? (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ overflowX: 'auto', pb: 0.5 }}\n >\n {listing.screenshots.map((url: string) => (\n // Click to zoom (AGL-869) — the strip thumbnails\n // are too small to actually evaluate a UI from.\n <Box\n key={url}\n component=\"img\"\n src={url}\n alt={`${listing?.displayName} screenshot`}\n loading=\"lazy\"\n onClick={() => setLightboxUrl(url)}\n sx={{\n height: 180,\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n cursor: 'zoom-in',\n }}\n />\n ))}\n </Stack>\n ) : null}\n {listing?.readme ? (\n <>\n <Divider />\n <ListingReadme readme={listing.readme} />\n </>\n ) : null}\n </Stack>\n </CardDisplay>\n ),\n },\n {\n size: { xs: 12, md: 8 },\n children: <ListingChangelog versions={versions} />,\n },\n {\n size: { xs: 12, md: 4 },\n children: (\n <Stack spacing={3}>\n {/* Install is the point of the page (AGL-1005). It used\n to be the LAST thing in the left column, under the\n README, the config table and the code sample — below\n the fold on any listing with real documentation.\n Here it leads the sidebar. */}\n <CardDisplay\n header={'Install'}\n help={pluginDocsHelp('installYourFirstPlugin', {\n anchor: '#step-4-targeting',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n {/* Price and version lead: the two facts someone\n decides on before they read anything else. */}\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'baseline' }}\n >\n <Typography variant=\"h6\">\n {priceUsd > 0 ? `$${priceUsd}` : 'Free'}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`v${listing?.latestVersion ?? '…'}`}\n </Typography>\n </Stack>\n {/*\n `WHAT'S INCLUDED` (AGL-2173), which the mockup\n puts under the description and this page did\n not have at all.\n\n Every row is derived from a fact the listing\n already carries — what the install physically\n produces, where it lands, review, licence,\n price. The mockup's own bullets (`12 responsive\n screens`) are publisher prose we do not\n collect, and counting screens would mean\n inventing a number.\n */}\n <Divider />\n <Stack spacing={0.75}>\n <Typography\n variant=\"overline\"\n color=\"text.secondary\"\n >\n {\"What's included\"}\n </Typography>\n {listingInclusions(listing ?? {}, {\n reviewedVersion:\n listing?.latestVersionReviewState ===\n 'approved',\n }).map((row) => (\n <Stack\n key={row.label}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'flex-start' }}\n >\n <MdiIcon\n path={\n row.tone === 'included'\n ? mdiCheckCircleOutline\n : mdiInformationOutline\n }\n size={0.8}\n color={\n row.tone === 'included'\n ? 'success'\n : 'disabled'\n }\n />\n <Typography variant=\"body2\">\n {row.label}\n </Typography>\n </Stack>\n ))}\n </Stack>\n <Divider />\n {/* Where it actually runs (AGL-997). At org scope an\n install is a SET of sites; this page used to\n resolve the single acting host and announce\n \"Installed on this site\", naming one arbitrary\n site and saying nothing about the others — and\n offering an Uninstall that was all-or-nothing. */}\n {/* The site set (AGL-997), shared with the\n installation detail page (AGL-1007) so the two\n surfaces cannot drift apart. */}\n {/* The version pair, for a viewer who already has this\n (AGL-1016). Without it the listing could advertise\n v2 while the workspace quietly ran v1 and no page\n said so — this is the same `resolveUpdateState` the\n Plugins index and installation page ask. */}\n {/* Say what this actually is, at the moment of\n doing it (AGL-1083). The Review status card says\n it too, but that describes a decision already\n made — this is the one that can still change it. */}\n {unreviewedInstall ? (\n <Alert severity=\"warning\" variant=\"outlined\">\n <Typography variant=\"body2\">\n {`No reviewer has approved v${listing?.latestVersion} yet.`}\n </Typography>\n <Typography variant=\"caption\" component=\"div\">\n {'You can install it because you publish it — ' +\n 'that is how you test a version before ' +\n 'submitting it. Nobody else can install it ' +\n 'until it is approved.'}\n </Typography>\n </Alert>\n ) : null}\n {installed &&\n updateStatus.state !== 'current' &&\n updateStatus.installedVersion ? (\n <Alert\n severity={\n updateStatus.state === 'update-available'\n ? 'info'\n : 'warning'\n }\n variant=\"outlined\"\n >\n {updateStateLabel(updateStatus)}\n </Alert>\n ) : null}\n {orgPluginScope ? (\n <PluginSiteSet\n listing={listing}\n hosts={hosts ?? []}\n orgInstall={orgInstall}\n latestVersion={offeredVersion}\n installPlan={installPlan}\n uninstall={uninstall}\n onChanged={() =>\n setPinsNonce((current) => current + 1)\n }\n />\n ) : null}\n {/* Existing state, told honestly (AGL-656): an org\n pin applies everywhere, and this site's own pin\n shadows it. Showing this is the difference between\n \"Add to this site\" lying and the truth. The\n org-scope panel above supersedes this for plugins\n (AGL-997); this remains for the per-site tab. */}\n {!orgPluginScope && isPlugin && installed ? (\n <Stack spacing={1}>\n {/* A confirmation, not a warning (AGL-1005): a\n tick and a sentence, where this used to be a\n pale alert with a red text link under it —\n which read as something having gone wrong. */}\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'flex-start' }}\n >\n <MdiIcon\n path={mdiCheckCircle.path}\n color=\"success\"\n sx={{ fontSize: 20, mt: '2px' }}\n />\n <Typography variant=\"body2\">\n {pluginState.shadowed\n ? `Installed on this site (v${installedVersion}), ` +\n 'overriding the organization-wide install.'\n : pluginState.scope === 'org'\n ? `Installed for the whole organization ` +\n `(v${installedVersion}) — available on every site.`\n : `Installed on this site (v${installedVersion}).`}\n {pluginState.updateAvailable\n ? ` A newer version (v${offeredVersion}) is available.`\n : ''}\n </Typography>\n </Stack>\n </Stack>\n ) : null}\n {/* Install targeting (AGL-773): at org scope, choose\n All sites vs a chosen subset. Only when NOT already\n installed — re-asking once it's settled would lie.\n The per-site tab keeps the simpler org/host choice\n (AGL-656) below until it's retired. */}\n {orgTargeting &&\n !installed &&\n !(orgPluginScope && orgInstall.installedAnywhere) ? (\n <Stack spacing={1.5} sx={{ maxWidth: 420 }}>\n <TextField\n select\n size=\"small\"\n label=\"Install to\"\n value={targeting}\n onChange={(event) =>\n setTargeting(\n event.target.value as InstallTargeting,\n )\n }\n helperText={\n targeting === 'all-sites'\n ? installTargets.includes('org')\n ? 'Available on every site — including sites you add later.'\n : `Installs to all ${allHostIds.length} site` +\n (allHostIds.length === 1 ? '' : 's') +\n \". New sites won't get it automatically.\"\n : 'Installs only to the sites you choose.'\n }\n >\n <MenuItem value=\"all-sites\">\n {'All sites'}\n </MenuItem>\n {canSelectSites ? (\n <MenuItem value=\"selected-sites\">\n {'Selected sites'}\n </MenuItem>\n ) : null}\n </TextField>\n {/* A visible checkbox list, not a multi-select\n (AGL-996). The MUI `select multiple` this\n replaced rendered its options as bare rows\n with no tick and no renderValue, so the\n control that decides WHERE third-party code\n gets installed could not be read at all:\n picked and unpicked sites looked identical,\n and the closed field showed raw host ids. */}\n {targeting === 'selected-sites' &&\n canSelectSites ? (\n <FormControl\n component=\"fieldset\"\n error={!selectedHostIds.length}\n >\n <FormLabel\n component=\"legend\"\n sx={{ typography: 'caption' }}\n >\n {'Sites'}\n </FormLabel>\n <FormGroup\n // Scrolls rather than pushing Install off\n // the page on an org with many sites.\n sx={{ maxHeight: 240, overflowY: 'auto' }}\n >\n {(hosts ?? []).map((host) => (\n <FormControlLabel\n key={host.id}\n control={\n <Checkbox\n size=\"small\"\n checked={selectedHostIds.includes(\n host.id,\n )}\n onChange={(event) =>\n setSelectedHostIds((current) =>\n event.target.checked\n ? [...current, host.id]\n : current.filter(\n (id) => id !== host.id,\n ),\n )\n }\n />\n }\n label={host.label}\n slotProps={{\n typography: { variant: 'body2' },\n }}\n />\n ))}\n </FormGroup>\n <FormHelperText>\n {selectedHostIds.length\n ? `${selectedHostIds.length} of ${\n (hosts ?? []).length\n } selected.`\n : 'Pick at least one site.'}\n </FormHelperText>\n </FormControl>\n ) : null}\n </Stack>\n ) : installTargets.length > 1 && !installed ? (\n <TextField\n select\n size=\"small\"\n label=\"Install to\"\n value={installScope}\n onChange={(event) =>\n setInstallScope(event.target.value as 'org' | 'host')\n }\n helperText={\n installScope === 'org'\n ? 'Available to every site in this organization. A site can still override it for itself.'\n : 'This site only.'\n }\n sx={{ maxWidth: 360 }}\n >\n <MenuItem value=\"org\">\n {'This organization — all sites'}\n </MenuItem>\n <MenuItem value=\"host\">{'This site only'}</MenuItem>\n </TextField>\n ) : null}\n {/* YOU OWN ONE — JUST NOT HERE (AGL-2331).\n A purchase licenses the organization that made it,\n so an agency owner who bought this for one client\n arrives in the next client's workspace to a plain\n Buy button. Saying nothing would make the second\n charge look like a double charge; this names the\n reason before the money moves, and the licences\n list says which workspace holds the first one. */}\n {mustBuy && licensedElsewhere ? (\n <Alert severity=\"info\" sx={{ mb: 1 }}>\n {'You already own this in another workspace. A ' +\n 'license covers one organization, so this one ' +\n 'needs its own.'}\n </Alert>\n ) : null}\n {/* THE LOOKUPS RAN SHORT, said where the money is.\n \"Not purchased\" and \"not installed\" are both an\n ABSENCE from a window, so a window that stopped\n early reads exactly like a licence nobody bought.\n The buy path is the one place that costs something\n to get wrong, so the notice sits above the\n button. */}\n {purchasesTruncated || installedTruncated ? (\n <Alert severity=\"warning\" sx={{ mb: 1 }}>\n {(purchasesTruncated\n ? `Checked against the first ${PURCHASE_LOOKUP_CEILING} of your purchases, ordered by id; you have more. `\n : `Checked against the first ${COMPONENT_LOOKUP_CEILING} components on this site, ordered by id; there are more. `) +\n 'If you already own or installed this, it may ' +\n 'not be reflected here — check your receipts ' +\n 'before buying again.'}\n </Alert>\n ) : null}\n {/* The org-scope panel owns install once anything is\n pinned (AGL-997) — it offers add, remove, update\n and promote, all of which this single button\n would only duplicate ambiguously. */}\n <Box\n sx={{\n display:\n orgPluginScope && orgInstall.installedAnywhere\n ? 'none'\n : undefined,\n }}\n >\n <Button\n // Full-width and contained (AGL-1005): in a\n // sidebar card this is the page's primary action,\n // and \"already installed and current\" is the only\n // state where it steps back to an outline.\n fullWidth\n variant={upToDate ? 'outlined' : 'contained'}\n color=\"primary\"\n disabled={\n Boolean(upToDate) ||\n !listing?.profileId ||\n // Nothing selected to install to (AGL-773).\n (orgTargeting &&\n !installed &&\n !mustBuy &&\n installPlanSteps.length === 0)\n }\n onClick={\n permissions.installPlugins\n ? () =>\n // Buying goes straight to Stripe checkout,\n // which is its own confirmation; a free or\n // entitled install confirms its targets\n // first (AGL-867). Updating a copied\n // artifact reviews the diff before writing\n // anything (AGL-1018).\n mustBuy\n ? buy(listing)\n : copiedUpdatable\n ? openUpdateReview()\n : setConfirmOpen(true)\n : () =>\n enqueueSnackbar(\n 'Your team role does not allow installing from the marketplace',\n { variant: 'warning', persist: false },\n )\n }\n >\n {upToDate\n ? `Installed (v${installedVersion})`\n : copiedUpdatable\n ? // Not \"Update\": pressing this shows what the\n // update would do and writes nothing. Without\n // an ordered version pair there is no \"to\n // vN\" to promise (AGL-1034), so it says the\n // honest, smaller thing.\n updateStatus.state === 'update-available'\n ? `Review update to v${offeredVersion}`\n : 'Review this version'\n : artifactInstall\n ? // Re-adding makes another dataset / another\n // draft, so this stays enabled (AGL-789). A\n // theme has no \"again\" — there is one per\n // site, and re-pressing this re-applies it.\n artifactType === 'theme'\n ? `Applied (v${installedVersion}) · re-apply`\n : `${\n artifactType === 'emailTemplate'\n ? 'Draft added'\n : 'Added'\n } (v${installedVersion}) · add again`\n : installed\n ? `Update to v${offeredVersion}`\n : mustBuy\n ? licensedElsewhere\n ? `Buy for this workspace — $${priceUsd}`\n : `Buy for $${priceUsd}`\n : unreviewedInstall\n ? `Install unreviewed v${listing?.latestVersion} for testing`\n : orgTargeting || installTargets.length > 1\n ? 'Install'\n : 'Add to this site'}\n </Button>\n </Box>\n {/* Uninstall from the listing too (AGL-881), not only\n the installed add-ons card; targets the effective\n pin's scope. Demoted to a quiet full-width\n secondary below the primary (AGL-1005) — it used\n to be red text directly under the \"installed\"\n notice, which made a successful install look like\n a problem to undo. */}\n {!orgPluginScope && isPlugin && installed ? (\n <Button\n fullWidth\n size=\"small\"\n color=\"inherit\"\n onClick={() =>\n setPendingUninstall({\n scope:\n pluginState.scope === 'org' ? 'org' : 'host',\n targets: resolveUninstallTargets(\n orgInstall,\n pluginState.scope === 'org' ? 'org' : 'host',\n hostId,\n ),\n })\n }\n >\n {pluginState.scope === 'org'\n ? 'Uninstall org-wide'\n : 'Uninstall'}\n </Button>\n ) : null}\n </Stack>\n </CardDisplay>\n <CardDisplay\n header={'Publisher'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#before-your-first-publish',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={0.5}>\n {/* Logo (AGL-1009): https-guarded at render even\n though the save route enforces it — the doc\n predates the guard. Falls back to an initial. */}\n <Avatar\n src={safePublisherHref(profile?.avatarUrl)}\n alt={profile?.displayName ?? 'Publisher'}\n variant=\"rounded\"\n sx={{ width: 40, height: 40, mb: 0.5 }}\n >\n {String(\n profile?.displayName ?? profile?.handle ?? '?',\n )\n .slice(0, 1)\n .toUpperCase()}\n </Avatar>\n {/* Link to the publisher's storefront (AGL-869):\n the org-scope publisher page at org scope, the\n per-site publisher page otherwise. */}\n <MuiLink\n href={\n !listing?.profileId\n ? undefined\n : orgScoped\n ? orgSlug\n ? buildRoute(\n Route.ORG_MARKETPLACE_PUBLISHER,\n {\n orgSlug,\n // Handle, not id (AGL-1001); the id\n // still resolves for the beat\n // before the profile loads.\n handle:\n profile?.handle ??\n listing.profileId,\n },\n )\n : undefined\n : orgSlug && subdomain\n ? buildRoute(\n Route.ORG_MARKETPLACE_PUBLISHER,\n {\n orgSlug,\n handle:\n profile?.handle ??\n listing.profileId,\n },\n )\n : undefined\n }\n color=\"primary\"\n underline=\"hover\"\n variant=\"body2\"\n >\n {profile?.displayName ??\n (profile?.handle ? `@${profile.handle}` : '…')}\n </MuiLink>\n {profile?.handle ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {`@${profile.handle}`}\n </Typography>\n ) : null}\n {profile?.bio ? (\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n >\n {profile.bio}\n </Typography>\n ) : null}\n {/* Support contact and social links (AGL-1009):\n a fixed icon set, every href https-guarded so\n a `javascript:` URL renders as nothing. */}\n {(() => {\n const links = [\n {\n key: 'website',\n label: 'Website',\n icon: mdiWeb.path,\n href: safePublisherHref(profile?.website),\n },\n {\n key: 'support',\n label: 'Support',\n icon: mdiLifebuoy.path,\n href: safePublisherHref(profile?.supportUrl),\n },\n {\n key: 'github',\n label: 'GitHub',\n icon: mdiGithub.path,\n href: safePublisherHref(profile?.githubUrl),\n },\n {\n key: 'x',\n label: 'X',\n icon: mdiTwitter.path,\n href: safePublisherHref(profile?.xUrl),\n },\n {\n key: 'linkedin',\n label: 'LinkedIn',\n icon: mdiLinkedin.path,\n href: safePublisherHref(profile?.linkedinUrl),\n },\n ].filter((entry) => entry.href)\n const email =\n typeof profile?.supportEmail === 'string' &&\n /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(\n profile.supportEmail,\n )\n ? profile.supportEmail\n : undefined\n if (!links.length && !email) return null\n return (\n <Stack direction=\"row\" spacing={0.5}>\n {email ? (\n <Tooltip title={`Support: ${email}`}>\n <IconButton\n size=\"small\"\n component=\"a\"\n href={`mailto:${email}`}\n aria-label={`Email support at ${email}`}\n >\n <MdiIcon\n path={mdiEmailOutline.path}\n fontSize=\"small\"\n />\n </IconButton>\n </Tooltip>\n ) : null}\n {links.map((entry) => (\n <Tooltip key={entry.key} title={entry.label}>\n <IconButton\n size=\"small\"\n component=\"a\"\n href={entry.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={entry.label}\n >\n <MdiIcon\n path={entry.icon}\n fontSize=\"small\"\n />\n </IconButton>\n </Tooltip>\n ))}\n </Stack>\n )\n })()}\n </Stack>\n </CardDisplay>\n {listing?.homepageUrl || listing?.repositoryUrl ? (\n <CardDisplay\n header={'Links'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#authoring-your-listing',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={0.5}>\n {listing?.homepageUrl ? (\n <MuiLink\n href={listing.homepageUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n color=\"primary\"\n underline=\"hover\"\n variant=\"body2\"\n >\n {'Homepage'}\n </MuiLink>\n ) : null}\n {listing?.repositoryUrl ? (\n <MuiLink\n href={listing.repositoryUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n color=\"primary\"\n underline=\"hover\"\n variant=\"body2\"\n >\n {'Source repository'}\n </MuiLink>\n ) : null}\n </Stack>\n </CardDisplay>\n ) : null}\n {/* ONE version timeline (AGL-869) — the plugin API's\n rich entries (changelog + trust) when present, the\n stored versionHistory otherwise. Two differently-\n shaped cards for the same idea read as unfinished. */}\n <CardDisplay\n header={'Version history'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#shipping-a-new-version',\n })}\n contentGutterX\n contentGutterY\n >\n {versions.length ? (\n <Stack spacing={1}>\n {versions.map((entry, index) => (\n <Stack key={entry.version} spacing={0.25}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"body2\">\n {`v${entry.version}`}\n </Typography>\n {index === 0 ? (\n <Chip size=\"small\" label=\"Latest\" />\n ) : null}\n {entry.trust === 'realm' ? (\n <Chip\n size=\"small\"\n color=\"success\"\n label=\"Realm-trusted\"\n />\n ) : null}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {entry.publishedAtMs\n ? new Date(\n entry.publishedAtMs,\n ).toLocaleDateString()\n : ''}\n </Typography>\n </Stack>\n {/* The changelog moved to its own card\n (AGL-976) — rendered as markdown, in the\n main column, with room to be read. This\n timeline keeps what it is good at: dates,\n trust, and who is still on which version. */}\n {/* Per-version installs (AGL-1036). The\n listing total cannot answer \"who is still\n on the old version\" — this can, and that is\n the question a publisher asks before\n changing anything. Hidden at zero rather\n than printed as \"0 installs\", which reads\n as a failure on a version nobody has\n reached yet. */}\n {/* Said in the same words as the header, and\n from the same reconciled numbers\n (AGL-1418). It used to lead with a bare\n \"3 installs\" that was a per-version\n all-time count sitting under a listing\n all-time count of 7 — two numbers, one\n word, one version. */}\n {entry.installCount ||\n entry.activeInstalls ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {`${entry.activeInstalls ?? 0} on this version`}\n {entry.installCount\n ? ` · ${entry.installCount} all time`\n : ''}\n </Typography>\n ) : null}\n </Stack>\n ))}\n {/* Named rather than absorbed (AGL-1418). Installs\n predating per-version tracking belong to no\n version here, and quietly dropping them made\n the breakdown disagree with the header. Saying\n the split is short is honest; inventing a\n version to hang them on is not. */}\n {installTotals?.untrackedActiveInstalls ||\n installTotals?.untrackedInstallCount ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {/* Both halves of the shortfall (AGL-2339).\n `untrackedActiveInstalls` was rendered and\n its sibling `untrackedInstallCount` was\n served and read by nothing — an asymmetry,\n not a decision. All-time is the LARGER\n number (an uninstall deletes its pin and\n leaves the accumulator alone), so showing\n only the active half made the all-time\n header look wrong by a margin the page\n could not explain. */}\n {`${installTotals.untrackedInstallCount} ` +\n `install${\n installTotals.untrackedInstallCount === 1\n ? ''\n : 's'\n } all-time and ${\n installTotals.untrackedActiveInstalls\n } still active predate per-version ` +\n 'tracking, and are not counted above.'}\n </Typography>\n ) : null}\n </Stack>\n ) : versionHistory.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Latest version: v${listing?.latestVersion ?? '…'}`}\n </Typography>\n ) : (\n <Stack spacing={0.5}>\n {versionHistory.map((entry, index) => (\n <Stack\n key={entry.version}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"body2\">\n {`v${entry.version}`}\n </Typography>\n {index === 0 ? (\n <Chip size=\"small\" label=\"Latest\" />\n ) : null}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {entry.publishedAt?.toDate\n ? entry.publishedAt\n .toDate()\n .toLocaleDateString()\n : ''}\n </Typography>\n </Stack>\n ))}\n </Stack>\n )}\n </CardDisplay>\n <ListingReviews\n listingId={listingId}\n listing={listing}\n />\n {/* The listing-level report (AGL-2435). Pre-publication\n review is plugin-only by design — a template or\n component is inert until someone installs it — so\n after-the-fact reporting is the ENTIRE safety net for\n every other artifact type, and it had no way in. */}\n <ReportTarget\n listingId={listingId}\n label={String(listing?.displayName ?? 'this listing')}\n />\n </Stack>\n ),\n },\n ]}\n />\n )}\n {/* Install confirmation (AGL-867): names the artifact, its version,\n and exactly which sites before any pin is written. */}\n <Dialog\n open={confirmOpen}\n onClose={() => setConfirmOpen(false)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n {unreviewedInstall\n ? 'Install an unreviewed version?'\n : installed\n ? 'Update this listing?'\n : 'Install this listing?'}\n </DialogTitle>\n <DialogContent dividers>\n <Stack spacing={1}>\n <Typography variant=\"body2\">\n {installed ? 'Update ' : 'Install '}\n <strong>{listing?.displayName}</strong>\n {listing\n ? ` (${listingArtifactLabel(listing)}, v${\n listing?.latestVersion\n })`\n : ''}\n {'.'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This will be installed to '}\n <strong>{installTargetSummary()}</strong>\n {'.'}\n </Typography>\n {/* Every site in this picker is publicly reachable — there\n is no staging site to prefer (AGL-1083). Saying \"we will\n mark the live ones\" would invent a distinction the\n platform does not have; saying they are all live is the\n part that should give someone pause. */}\n {unreviewedInstall ? (\n <Alert severity=\"warning\">\n {`v${listing?.latestVersion} has not passed review. ` +\n 'Every site you install it to is publicly reachable — ' +\n 'there is no staging site here — so unreviewed code ' +\n 'will serve real visitors until you uninstall it.'}\n </Alert>\n ) : null}\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmOpen(false)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={runInstall}\n >\n {unreviewedInstall\n ? 'Install for testing'\n : installed\n ? 'Update'\n : 'Install'}\n </Button>\n </DialogActions>\n </Dialog>\n {/* Updating a copy, previewed field by field (AGL-1018). Install\n writes the publisher's version over yours; this shows what would\n be lost first, and keeps your edits by default. */}\n <ArtifactUpdateDialog\n open={updateOpen}\n onClose={() => setUpdateOpen(false)}\n artifactName={listing?.displayName ?? 'this listing'}\n preview={updatePreview}\n loading={updateLoading}\n onApplyMerge={(takePaths, confirmDestructive) =>\n void runUpdate('merge', takePaths, confirmDestructive)\n }\n onApplyCopy={() => void runCopy()}\n />\n {/* What an uninstall would break, before it happens (AGL-1027). */}\n <UninstallImpactDialog\n open={pendingUninstall !== null}\n listing={listing}\n scope={pendingUninstall?.scope ?? 'host'}\n targets={pendingUninstall?.targets ?? []}\n onCancel={() => setPendingUninstall(null)}\n onConfirm={async () => {\n const target = pendingUninstall\n setPendingUninstall(null)\n if (!target) return\n await uninstall(listing, target.scope)\n setPinsNonce((nonce) => nonce + 1)\n }}\n />\n {/* Screenshot lightbox (AGL-869). */}\n <Dialog\n open={Boolean(lightboxUrl)}\n onClose={() => setLightboxUrl(null)}\n maxWidth=\"lg\"\n >\n {lightboxUrl ? (\n <Box\n component=\"img\"\n src={lightboxUrl}\n alt={`${listing?.displayName} screenshot`}\n onClick={() => setLightboxUrl(null)}\n sx={{\n display: 'block',\n maxWidth: '100%',\n maxHeight: '85vh',\n cursor: 'zoom-out',\n }}\n />\n ) : null}\n </Dialog>\n </Container>\n </>\n )\n}\n\nexport default MarketplaceListingContent\n"],"names":["LISTING_README_MAX_CHARS","listingArtifactType","installsUnreviewedFallback","listingArtifactLabel","listingInclusions","hasLivePurchaseOf","hasOrgLicenceOf","licensedOrgIdsFor","installTargetsFor","isListingDeleted","isPrivateListing","resolveInstallPlan","resolveOrgInstallSummary","resolvePluginInstallState","resolveUninstallTargets","safePublisherHref","UninstallImpactDialog","ListingImage","buildRoute","parseMarkdownLite","PLATFORM_BRAND_NAME","offeredPluginVersion","PLUGIN_HOST_ABI_VERSION","pluginDocsHelp","resolveMarkdownLink","resolveMediaSrc","resolveUpdateState","Route","updateStateLabel","mdiCheckCircle","mdiCheckCircleOutline","mdiEmailOutline","mdiGithub","mdiInformationOutline","mdiLifebuoy","mdiLinkedin","mdiStorefrontOutline","mdiTwitter","mdiWeb","AppLink","CardDisplay","Container","GridItems","MdiIcon","NextPageTitle","useSnackbar","Alert","Avatar","Box","Button","Checkbox","Chip","Dialog","DialogActions","DialogContent","DialogTitle","Divider","FormControl","FormControlLabel","FormGroup","FormHelperText","FormLabel","IconButton","Link","MuiLink","Rating","Stack","Tooltip","Typography","collection","doc","documentId","getDoc","limit","orderBy","query","where","useEffect","useMemo","useState","useConsoleHostRoute","useFirestore","useFirestoreCollection","useFirestoreDoc","useHostOrgId","useUser","useScopeTokens","ceilingedWindow","collectionCeiling","ListingReviews","ReportTarget","PluginSiteSet","MenuItem","TextField","useMarketplaceActions","useArtifactUpdate","ArtifactUpdateDialog","COMPONENT_LOOKUP_CEILING","PURCHASE_LOOKUP_CEILING","ARTIFACT_INSTALL_CEILING","renderInlines","inlines","map","inline","index","type","strong","text","em","link","href","span","target","rel","color","underline","ListingChangelog","versions","entries","filter","entry","String","changelog","trim","length","header","help","anchor","contentGutterX","contentGutterY","spacing","direction","sx","alignItems","flexWrap","variant","version","size","label","trust","publishedAtMs","Date","toLocaleDateString","ListingReadme","readme","blocks","slice","block","level","component","src","alt","loading","maxWidth","borderRadius","border","borderColor","my","items","item","itemIndex","start","p","overflowX","bgcolor","typography","fontFamily","code","borderCollapse","width","px","py","thead","tr","cell","cellIndex","textAlign","align","fontWeight","tbody","rows","row","rowIndex","mx","pl","borderLeft","fontStyle","listingIsMissing","listing","status","$id","MarketplaceListingContent","hostId","listingId","permissions","orgScoped","orgSlug","orgSlugProp","hosts","pluginState","profile","componentInstall","resolvedOrgSlug","subdomain","firestore","data","user","enqueueSnackbar","orgId","install","installPlan","buy","uninstall","pendingUninstall","setPendingUninstall","installScope","setInstallScope","confirmOpen","setConfirmOpen","preview","updatePreview","updateLoading","loadPreview","applyUpdate","setPreview","setUpdatePreview","updateOpen","setUpdateOpen","lightboxUrl","setLightboxUrl","orgTargeting","Boolean","targeting","setTargeting","selectedHostIds","setSelectedHostIds","allHostIds","h","id","viewerOrgId","setViewerOrgId","active","then","snapshot","get","catch","undefined","idField","installTargets","profileId","installedRead","installedDocs","truncated","installedTruncated","purchaseRead","uid","purchaseDocs","purchasesTruncated","artifactType","isPlugin","hostPin","orgPin","sitePins","setSitePins","pinsNonce","setPinsNonce","hostIdsKey","host","join","Promise","all","exists","Object","fromEntries","tokens","scopeTokens","orgWide","viewerOrgWide","loaded","scopeLoaded","needsScope","datasetInstalls","confirmDisappearances","emailInstalls","themeHostDoc","artifactInstall","hit","find","deletedAt","source","installedFrom","stamp","themeInstalledFrom","revocation","offeredVersion","latestVersion","unreviewedInstall","installingVersion","setVersions","totals","setTotals","fetch","encodeURIComponent","response","ok","json","payload","activeInstalls","installCount","Number","untrackedActiveInstalls","untrackedInstallCount","installTotals","stored","NaN","isFinite","latestEntry","realmTrusted","some","abiIncompatible","hostAbi","definition","marketplace","purchased","licensedElsewhere","licensed","missing","marketplaceHref","ORG_MARKETPLACE","installed","scope","installedVersion","upToDate","updateAvailable","updateStatus","priceUsd","mustBuy","installTargetScope","canSelectSites","includes","installPlanSteps","versionHistory","Array","isArray","sort","a","b","installTargetSummary","names","step","orgPluginScope","orgInstall","runSiteEdit","work","current","copiedUpdatable","state","openUpdateReview","runCopy","runUpdate","onDiverged","mode","takePaths","confirmDestructive","done","runInstall","screen","displayName","gutterY","path","fontSize","masonry","xs","md","children","previewImageUrl","maxHeight","objectFit","logoUrl","height","categories","category","license","reviewStatus","title","latestVersionReviewState","ratingCount","readOnly","precision","value","ratingAverage","description","severity","screenshots","pb","url","onClick","cursor","reviewedVersion","tone","onChanged","mt","shadowed","installedAnywhere","select","onChange","event","helperText","error","overflowY","control","checked","slotProps","mb","display","fullWidth","disabled","installPlugins","persist","targets","avatarUrl","handle","toUpperCase","ORG_MARKETPLACE_PUBLISHER","bio","links","key","icon","website","supportUrl","githubUrl","xUrl","linkedinUrl","email","supportEmail","test","aria-label","homepageUrl","repositoryUrl","publishedAt","toDate","open","onClose","dividers","artifactName","onApplyMerge","onApplyCopy","onCancel","onConfirm","nonce"],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type SxProps, type Theme } from '@mui/material';
|
|
2
|
+
/**
|
|
3
|
+
* A listing's publisher-chosen artwork, resolved (AGL-1424).
|
|
4
|
+
*
|
|
5
|
+
* `marketplaceListings.previewImageUrl` was rendered by handing the stored
|
|
6
|
+
* string straight to a `src`, on the browse card and again at the top of the
|
|
7
|
+
* detail page. That is a buyer-facing surface, so the stored raw
|
|
8
|
+
* `firebasestorage` URL leaks the bucket path and the publishing org's id,
|
|
9
|
+
* gets no CDN delivery or WebP variants, and — because the embedded
|
|
10
|
+
* `&token=` is regenerated by `media/replace/route.ts` on every replace, and
|
|
11
|
+
* an AGL-1215 folder move copies the object and deletes the original — rots
|
|
12
|
+
* silently the first time the publisher touches the asset.
|
|
13
|
+
*
|
|
14
|
+
* The repair is a `media:{scope}/{mediaId}` reference in the field, which
|
|
15
|
+
* names the ASSET rather than a location. This component is the render half
|
|
16
|
+
* of that, and it has to ship BEFORE any value is converted: to a renderer
|
|
17
|
+
* that does not know the scheme a reference is just a nonsense URL, and the
|
|
18
|
+
* listing image goes dark. That ordering is the whole lesson of AGL-1407.
|
|
19
|
+
*
|
|
20
|
+
* {@link resolveMediaSrc} carries the three stored generations, so nothing
|
|
21
|
+
* needs converting for this to be correct today: a reference becomes the CDN
|
|
22
|
+
* path, and a raw storage URL, a legacy `/api/media/cdn/…` path and an
|
|
23
|
+
* author-typed external URL are all passed through untouched. Both apps that
|
|
24
|
+
* render marketplace UI serve `/api/media/cdn/[...path]`, so the root-relative
|
|
25
|
+
* result resolves on the console origin the listing pages are served from.
|
|
26
|
+
*
|
|
27
|
+
* Renders NOTHING when there is no usable source — absent, empty, or a
|
|
28
|
+
* `media:` value too malformed to resolve. Each call site previously wrote
|
|
29
|
+
* that conditional itself; a malformed reference reaching a `src` would be a
|
|
30
|
+
* broken-image icon on a store page and a console error nobody reads.
|
|
31
|
+
*
|
|
32
|
+
* A plain MUI `Box component="img"`, deliberately: the besigner's standalone
|
|
33
|
+
* image block is what broke tenant SSR in AGL-579, and every image on these
|
|
34
|
+
* pages is already this element. This adds a resolver, not a rendering
|
|
35
|
+
* strategy.
|
|
36
|
+
*/
|
|
37
|
+
export interface ListingImageProps {
|
|
38
|
+
/** The stored value: a `media:` reference, or any URL. */
|
|
39
|
+
src?: string | null;
|
|
40
|
+
alt: string;
|
|
41
|
+
sx?: SxProps<Theme>;
|
|
42
|
+
loading?: 'eager' | 'lazy';
|
|
43
|
+
onClick?: () => void;
|
|
44
|
+
}
|
|
45
|
+
export declare function ListingImage({ src, alt, sx, loading, onClick, }: ListingImageProps): import("react").JSX.Element;
|
|
46
|
+
export default ListingImage;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
+
import { Box } from "@mui/material";
|
|
20
|
+
import { resolveMediaSrc } from "@aglyn/aglyn/app-utils/media-ref";
|
|
21
|
+
export function ListingImage({ src, alt, sx, loading, onClick }) {
|
|
22
|
+
const resolved = resolveMediaSrc(src);
|
|
23
|
+
if (!resolved) return null;
|
|
24
|
+
return /*#__PURE__*/ _jsx(Box, _extends({
|
|
25
|
+
component: "img",
|
|
26
|
+
src: resolved,
|
|
27
|
+
alt: alt
|
|
28
|
+
}, loading ? {
|
|
29
|
+
loading
|
|
30
|
+
} : {}, onClick ? {
|
|
31
|
+
onClick
|
|
32
|
+
} : {}, {
|
|
33
|
+
sx: sx
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
export default ListingImage;
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=listing-image.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/listing-image.component.tsx"],"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'use client'\n\nimport { Box, type SxProps, type Theme } from '@mui/material'\nimport { resolveMediaSrc } from '@aglyn/aglyn/app-utils/media-ref'\n\n/**\n * A listing's publisher-chosen artwork, resolved (AGL-1424).\n *\n * `marketplaceListings.previewImageUrl` was rendered by handing the stored\n * string straight to a `src`, on the browse card and again at the top of the\n * detail page. That is a buyer-facing surface, so the stored raw\n * `firebasestorage` URL leaks the bucket path and the publishing org's id,\n * gets no CDN delivery or WebP variants, and — because the embedded\n * `&token=` is regenerated by `media/replace/route.ts` on every replace, and\n * an AGL-1215 folder move copies the object and deletes the original — rots\n * silently the first time the publisher touches the asset.\n *\n * The repair is a `media:{scope}/{mediaId}` reference in the field, which\n * names the ASSET rather than a location. This component is the render half\n * of that, and it has to ship BEFORE any value is converted: to a renderer\n * that does not know the scheme a reference is just a nonsense URL, and the\n * listing image goes dark. That ordering is the whole lesson of AGL-1407.\n *\n * {@link resolveMediaSrc} carries the three stored generations, so nothing\n * needs converting for this to be correct today: a reference becomes the CDN\n * path, and a raw storage URL, a legacy `/api/media/cdn/…` path and an\n * author-typed external URL are all passed through untouched. Both apps that\n * render marketplace UI serve `/api/media/cdn/[...path]`, so the root-relative\n * result resolves on the console origin the listing pages are served from.\n *\n * Renders NOTHING when there is no usable source — absent, empty, or a\n * `media:` value too malformed to resolve. Each call site previously wrote\n * that conditional itself; a malformed reference reaching a `src` would be a\n * broken-image icon on a store page and a console error nobody reads.\n *\n * A plain MUI `Box component=\"img\"`, deliberately: the besigner's standalone\n * image block is what broke tenant SSR in AGL-579, and every image on these\n * pages is already this element. This adds a resolver, not a rendering\n * strategy.\n */\nexport interface ListingImageProps {\n /** The stored value: a `media:` reference, or any URL. */\n src?: string | null\n alt: string\n sx?: SxProps<Theme>\n loading?: 'eager' | 'lazy'\n onClick?: () => void\n}\n\nexport function ListingImage({\n src,\n alt,\n sx,\n loading,\n onClick,\n}: ListingImageProps) {\n const resolved = resolveMediaSrc(src)\n if (!resolved) return null\n return (\n <Box\n component=\"img\"\n src={resolved}\n alt={alt}\n {...(loading ? { loading } : {})}\n {...(onClick ? { onClick } : {})}\n sx={sx}\n />\n )\n}\n\nexport default ListingImage\n"],"names":["Box","resolveMediaSrc","ListingImage","src","alt","sx","loading","onClick","resolved","component"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,GAAG,QAAkC,gBAAe;AAC7D,SAASC,eAAe,QAAQ,mCAAkC;AA8ClE,OAAO,SAASC,aAAa,EAC3BC,GAAG,EACHC,GAAG,EACHC,EAAE,EACFC,OAAO,EACPC,OAAO,EACW;IAClB,MAAMC,WAAWP,gBAAgBE;IACjC,IAAI,CAACK,UAAU,OAAO;IACtB,qBACE,KAACR;QACCS,WAAU;QACVN,KAAKK;QACLJ,KAAKA;OACAE,UAAU;QAAEA;IAAQ,IAAI,CAAC,GACzBC,UAAU;QAAEA;IAAQ,IAAI,CAAC;QAC9BF,IAAIA;;AAGV;AAEA,eAAeH,aAAY"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ratings and comments on a listing (AGL-655).
|
|
3
|
+
*
|
|
4
|
+
* Reads the subcollection directly — it is public-read, so there is no
|
|
5
|
+
* value in proxying it through an API. Writes go through
|
|
6
|
+
* `/api/marketplace/reviews`, which owns every rule that matters: only
|
|
7
|
+
* accounts that installed the listing may rate it, the publishing org
|
|
8
|
+
* cannot review itself, and the aggregates it maintains are frozen from
|
|
9
|
+
* client writes.
|
|
10
|
+
*
|
|
11
|
+
* The star input is offered to everyone and refused server-side rather than
|
|
12
|
+
* hidden, because "you must install this to rate it" is worth saying out
|
|
13
|
+
* loud — a control that silently does nothing teaches nothing.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ListingReviews({ listingId, listing, }: {
|
|
16
|
+
listingId: string;
|
|
17
|
+
listing: Record<string, any> | undefined;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
export declare namespace ListingReviews {
|
|
20
|
+
var displayName: string;
|
|
21
|
+
}
|
|
22
|
+
export default ListingReviews;
|