@aglyn/plugins-marketplace 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/lib/components/listing-content.component.js +78 -36
- package/src/lib/components/listing-content.component.js.map +1 -1
- package/src/lib/components/listing-detail-page.component.js +22 -9
- package/src/lib/components/listing-detail-page.component.js.map +1 -1
- package/src/lib/components/listing-review-status.component.d.ts +8 -0
- package/src/lib/components/listing-review-status.component.js +23 -3
- package/src/lib/components/listing-review-status.component.js.map +1 -1
- package/src/lib/components/listing-verification-request.component.d.ts +8 -0
- package/src/lib/components/listing-verification-request.component.js +12 -5
- package/src/lib/components/listing-verification-request.component.js.map +1 -1
- package/src/lib/components/marketplace-hub.component.js +2 -1
- package/src/lib/components/marketplace-hub.component.js.map +1 -1
- package/src/lib/components/org-seller-panel.component.d.ts +10 -0
- package/src/lib/components/org-seller-panel.component.js +26 -4
- package/src/lib/components/org-seller-panel.component.js.map +1 -1
- package/src/lib/components/starter-picker-shelf.component.js +13 -8
- package/src/lib/components/starter-picker-shelf.component.js.map +1 -1
- package/src/lib/declarations.d.ts +2 -1
- package/src/lib/declarations.js +5 -1
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/model/marketplace-publisher-permissions.d.ts +26 -0
- package/src/lib/model/marketplace-publisher-permissions.js +64 -0
- package/src/lib/model/marketplace-publisher-permissions.js.map +1 -0
- package/src/lib/model/marketplace.js +2 -1
- package/src/lib/model/marketplace.js.map +1 -1
- package/src/lib/model/own-listing.d.ts +52 -0
- package/src/lib/model/own-listing.js +72 -0
- package/src/lib/model/own-listing.js.map +1 -0
- package/src/lib/model/starter-query.js +2 -0
- package/src/lib/model/starter-query.js.map +1 -1
- package/src/lib/server/connect.js +11 -5
- package/src/lib/server/connect.js.map +1 -1
- package/src/lib/server/install-dataset-schema.js +10 -2
- package/src/lib/server/install-dataset-schema.js.map +1 -1
- package/src/lib/server/install-email-starter.js +8 -2
- package/src/lib/server/install-email-starter.js.map +1 -1
- package/src/lib/server/install-email-template.js +8 -2
- package/src/lib/server/install-email-template.js.map +1 -1
- package/src/lib/server/install-layout.js +8 -2
- package/src/lib/server/install-layout.js.map +1 -1
- package/src/lib/server/install-plugin.js +24 -20
- package/src/lib/server/install-plugin.js.map +1 -1
- package/src/lib/server/install-template.js +8 -5
- package/src/lib/server/install-template.js.map +1 -1
- package/src/lib/server/install-theme.js +8 -2
- package/src/lib/server/install-theme.js.map +1 -1
- package/src/lib/server/install.js +10 -5
- package/src/lib/server/install.js.map +1 -1
- package/src/lib/server/listing-versions.js +24 -9
- package/src/lib/server/listing-versions.js.map +1 -1
- package/src/lib/server/own-listing.d.ts +46 -0
- package/src/lib/server/own-listing.js +52 -0
- package/src/lib/server/own-listing.js.map +1 -0
- package/src/lib/server/preview-image.d.ts +1 -1
- package/src/lib/server/preview-image.js +9 -8
- package/src/lib/server/preview-image.js.map +1 -1
- package/src/lib/server/publish-plugin.js +17 -19
- package/src/lib/server/publish-plugin.js.map +1 -1
- package/src/lib/server/publisher-permissions.d.ts +63 -0
- package/src/lib/server/publisher-permissions.js +51 -0
- package/src/lib/server/publisher-permissions.js.map +1 -0
- package/src/lib/server/publisher-profile-save.d.ts +4 -2
- package/src/lib/server/publisher-profile-save.js +12 -5
- package/src/lib/server/publisher-profile-save.js.map +1 -1
- package/src/lib/server/publisher-profile.d.ts +18 -6
- package/src/lib/server/publisher-profile.js +19 -8
- package/src/lib/server/publisher-profile.js.map +1 -1
- package/src/lib/server/reviews.js +6 -5
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/sale-risk.d.ts +0 -6
- package/src/lib/server/sale-risk.js +0 -9
- package/src/lib/server/sale-risk.js.map +1 -1
- package/src/lib/server/sale.js +10 -9
- package/src/lib/server/sale.js.map +1 -1
- package/src/lib/server/site-starter-source.js +43 -17
- package/src/lib/server/site-starter-source.js.map +1 -1
- package/src/lib/server/update-artifact.js +11 -4
- package/src/lib/server/update-artifact.js.map +1 -1
- package/src/lib/server/verification-request.js +23 -7
- package/src/lib/server/verification-request.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/starter-picker-shelf.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 { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { resolveMediaSrc } from '@aglyn/aglyn/app-utils/media-ref'\nimport type { SiteStarterFacets } from '@aglyn/aglyn/app-utils/site-starter'\nimport type { ConsoleHostStarterPickerZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport type { SiteStarterSummary } from '@aglyn/aglyn/plugin-manager/plugin-site-starters'\nimport { mdiWeb } from '@aglyn/shared-data-mdi'\nimport {\n OptionCardGrid,\n type OptionCard,\n type OptionCardChip,\n type OptionCardImage,\n} from '@aglyn/shared-ui-jsx/components/option-card-grid.component'\nimport {\n Alert,\n Box,\n Button,\n Link,\n LinearProgress,\n Skeleton,\n Stack,\n type SxProps,\n type Theme,\n} from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useStarterAnswers } from '../hooks/use-starter-answers'\nimport { useStarterPurchase } from '../hooks/use-starter-purchase'\nimport { useStarterSearch } from '../hooks/use-starter-search'\nimport { starterCardFacts, starterPriceLabel, type StarterCardFact } from '../model/starter-query'\n\n/**\n * What a picked starter's price or licence says, held at the foot of the\n * visible cards while the shelf is in view, so \"Buy and continue\" is beside\n * whichever card was clicked rather than below all of them.\n */\nconst PICK_NOTE_SX: SxProps<Theme> = {\n position: 'sticky',\n bottom: (theme) => theme.spacing(2),\n zIndex: 1,\n boxShadow: 3,\n}\n\n/**\n * The payment, where the note was, on its own surface. It may fill the window\n * below the app bar, so a form that has grown keeps its button on screen; a\n * smaller window scrolls inside it.\n */\nconst PAY_PANEL_SX: SxProps<Theme> = {\n position: 'sticky',\n bottom: (theme) => theme.spacing(2),\n zIndex: 1,\n boxShadow: 3,\n p: 2,\n borderRadius: 1,\n bgcolor: 'background.paper',\n maxHeight: (theme) => `calc(100dvh - ${theme.spacing(10)})`,\n overflow: 'auto',\n}\n\n/** The guide to site starters, linked from what the shelf says when it has nothing to show. */\nconst STARTERS_HELP = pluginDocsHelp('siteStarters')\n\n/**\n * A starter's preview as the card draws it: the size the platform's own\n * style previews are rendered at (square), so a row of cards stays level and\n * a publisher's picture is cropped to the same shape from its top.\n */\nconst PREVIEW_SIZE = { width: 800, height: 800 } as const\n\n/** How many placeholder cards stand in for the first answer. */\nconst PLACEHOLDER_CARDS = 3\n\n/** Statuses that mean this workspace may not have starters offered here: the dialog's own choice instead. */\nconst REFUSED = new Set([401, 403, 503])\n\n/** How each fact's chip is colored, from the theme: the price as the marketplace's own cards color it. */\nfunction chipOf(fact: StarterCardFact, row: SiteStarterSummary): OptionCardChip {\n switch (fact.key) {\n case 'price':\n return row.priceUsd > 0\n ? { label: fact.label, color: 'primary', variant: 'filled' }\n : { label: fact.label, color: 'success', variant: 'outlined' }\n case 'official':\n return { label: fact.label, color: 'primary', variant: 'outlined' }\n case 'ai':\n return { label: fact.label, color: 'secondary', variant: 'outlined' }\n default:\n return { label: fact.label }\n }\n}\n\n/** The picture a card draws, resolved the way the listing's own pages resolve it. */\nfunction previewOf(row: SiteStarterSummary): OptionCardImage | null {\n const src = resolveMediaSrc(row.previewImageUrl)\n if (!src) return null\n return { src, alt: `A preview of ${row.displayName || 'this starter'}`, ...PREVIEW_SIZE }\n}\n\n/** One starter as a card in the shared option grid. */\nfunction cardOf(row: SiteStarterSummary): OptionCard {\n const image = previewOf(row)\n return {\n id: row.listingId,\n title: row.displayName || 'Untitled starter',\n ...(row.authorName ? { description: `By ${row.authorName}` } : {}),\n ...(image ? { image } : { icon: mdiWeb.path }),\n chips: starterCardFacts(row).map((fact) => chipOf(fact, row)),\n }\n}\n\nconst narrowed = (filter: Partial<SiteStarterFacets>): boolean =>\n (['kind', 'base', 'fonts'] as const).some((key) => typeof filter[key] === 'string' && filter[key] !== '')\n\n/** A row with what the dialog or a purchase knows about owning it laid over the search's answer. */\nconst ownedOf = (row: SiteStarterSummary, override: boolean | undefined): boolean =>\n override ?? row.owned === true\n\n/** What an answer with no starters says, in the words of what was asked. */\nfunction emptyMessage(props: ConsoleHostStarterPickerZoneProps): string {\n if (props.search.trim()) return 'No starters match — try fewer words'\n if (narrowed(props.filter ?? {})) return 'No starters match these choices — try another'\n return props.mode === 'ai' ? 'No AI starters yet' : 'No starters yet'\n}\n\n/**\n * The marketplace's starters in \"Choose your starter\" (AGL-4049): the\n * `hostStarterPicker` zone, drawn before the site exists.\n *\n * Lists what the dialog asks for — its mode, its search words and its\n * filters — as cards of the shared option grid: a picture, the name, who made\n * it, and its price, kind, page count and the \"AI\" and platform marks as\n * chips. NOTHING is selected when it opens; a person picks, and the pick goes\n * to the dialog through `onPick`. It creates nothing: the dialog creates the\n * site from the starter it was handed.\n *\n * `ready` tells the dialog whether a picker is on screen. The first answer\n * decides: starters, or a search that found none (its empty state is a\n * picker with nothing in it yet), answer `true`; a workspace refused the\n * starters (no permission, the release flag off, no source) or a catalog with\n * nothing in it answers `false`, and the dialog offers its own choice\n * instead. Once shown, a later refusal hands back the same way; a later\n * failure is said here with a way to ask again.\n *\n * A picked starter with a price the workspace has not paid says so under\n * the cards, with \"Buy and continue\": the marketplace's payment, in place, on\n * the card on file, with the site still to be created. One it owns says that\n * instead. The dialog's own `selected` wins over the shelf's pick: it is how\n * a pick restored after paying is shown chosen, and how one the create\n * refused is cleared.\n *\n * An AI starter the workspace may use — free, owned, or just bought — has\n * the answers it carries read once it is picked (AGL-4049 phase 4), and\n * handed to the dialog with it (`onPick(pick, { answers })`), which goes on\n * to the AI start's questions with them. A priced one not yet bought is\n * never read: its answers are what it sells, and the door would ask payment\n * for them. A door that still asks is told back to the dialog as unowned.\n */\nexport function StarterPickerShelf(props: ConsoleHostStarterPickerZoneProps) {\n const { orgId, orgSlug, mode, search, filter, onPick, ready, selected } = props\n // The pick the dialog opened on, restored after paying for it: asked for\n // by every search from then on, so it is listed (first) wherever the\n // search would have put it, and never moves under the person's cursor.\n const [restored] = useState(() => selected?.listingId ?? null)\n const found = useStarterSearch({ orgId, mode, word: search, filter, include: restored })\n const [picked, setPicked] = useState<string | null>(null)\n const [shown, setShown] = useState(false)\n // Starters a purchase attempt found this workspace already owns.\n const [ownedHere, setOwnedHere] = useState<ReadonlySet<string>>(() => new Set())\n // AI starters whose answers the door still asked payment for (AGL-4049).\n const [unpaidHere, setUnpaidHere] = useState<ReadonlySet<string>>(() => new Set())\n const purchase = useStarterPurchase(orgId, orgSlug)\n const starterAnswers = useStarterAnswers(orgId)\n const value = selected !== undefined ? (selected?.listingId ?? null) : picked\n const pickedRow = value ? (found.rows.find((row) => row.listingId === value) ?? null) : null\n const ownedOverride = (row: SiteStarterSummary): boolean | undefined =>\n ownedHere.has(row.listingId)\n ? true\n : unpaidHere.has(row.listingId)\n ? false\n : selected?.listingId === row.listingId\n ? selected.owned\n : undefined\n\n const refused = found.error !== null && REFUSED.has(found.error.status)\n // `null` until the first answer, which is the only one that may decide\n // there is nothing to show; after that only a refusal takes it back.\n const verdict: boolean | null = !found.settled\n ? null\n : refused\n ? false\n : shown\n ? true\n : found.error\n ? false\n : found.rows.length > 0 || search.trim() !== '' || narrowed(filter ?? {})\n\n useEffect(() => {\n if (verdict === true) setShown(true)\n if (verdict === false) setShown(false)\n }, [verdict])\n\n // Each distinct verdict once, whatever identity the dialog's callback has.\n const readyRef = useRef(ready)\n readyRef.current = ready\n const reported = useRef<boolean | null>(null)\n useEffect(() => {\n if (verdict === null || reported.current === verdict) return\n reported.current = verdict\n readyRef.current(verdict)\n }, [verdict])\n\n // A pick the dialog restored is handed back once the shelf has read it,\n // so the dialog holds the starter as the search describes it.\n const onPickRef = useRef(onPick)\n onPickRef.current = onPick\n const handedBack = useRef(false)\n useEffect(() => {\n if (!restored || handedBack.current || !pickedRow || pickedRow.listingId !== restored) return\n handedBack.current = true\n const override = ownedOverride(pickedRow)\n onPickRef.current(override === undefined ? pickedRow : { ...pickedRow, owned: override })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [restored, pickedRow])\n\n // The picked AI starter's answers (AGL-4049), read once it is one the\n // workspace may use; keyed on the listing and whether it is owned, so a\n // purchase that makes it usable reads it, and nothing reads it twice.\n const pickedOwned = pickedRow ? ownedOf(pickedRow, ownedOverride(pickedRow)) : false\n const answersKey =\n pickedRow && pickedRow.facets.mode === 'ai' && (pickedRow.priceUsd <= 0 || pickedOwned)\n ? `${pickedRow.listingId}:${pickedOwned}`\n : null\n const [reading, setReading] = useState<{ key: string; failed: string | null } | null>(null)\n const [readAttempt, setReadAttempt] = useState(0)\n const askedAnswers = useRef<string | null>(null)\n useEffect(() => {\n if (!answersKey || !pickedRow || askedAnswers.current === answersKey) return\n askedAnswers.current = answersKey\n const row = pickedRow\n const override = ownedOverride(row)\n const handed = override === undefined ? row : { ...row, owned: override }\n setReading({ key: answersKey, failed: null })\n void starterAnswers.read(row.listingId).then((outcome) => {\n if (askedAnswers.current !== answersKey) return\n if (outcome.status === 'failed') return setReading({ key: answersKey, failed: outcome.message })\n setReading(null)\n if (outcome.status === 'ready') return onPickRef.current(handed, { answers: outcome.answers })\n setUnpaidHere((current) => new Set(current).add(row.listingId))\n onPickRef.current({ ...row, owned: false })\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [answersKey, readAttempt])\n const readingPicked = reading !== null && reading.key === answersKey ? reading : null\n const readAgain = () => {\n askedAnswers.current = null\n setReadAttempt((count) => count + 1)\n }\n\n const options = useMemo(() => found.rows.map(cardOf), [found.rows])\n\n const buy = async (row: SiteStarterSummary) => {\n const outcome = await purchase.buy({ listingId: row.listingId, displayName: row.displayName })\n if (outcome !== 'owned') return\n setOwnedHere((current) => new Set(current).add(row.listingId))\n setUnpaidHere((current) => {\n const next = new Set(current)\n next.delete(row.listingId)\n return next\n })\n onPick({ ...row, owned: true })\n }\n\n if (verdict === false) return null\n if (verdict === null) {\n return (\n <Box\n aria-busy\n aria-label=\"Loading starters\"\n sx={{ display: 'grid', gap: 2, gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, minmax(0, 1fr))', md: 'repeat(3, minmax(0, 1fr))' } }}\n >\n {Array.from({ length: PLACEHOLDER_CARDS }, (_, index) => (\n <Skeleton key={index} variant=\"rounded\" sx={{ height: 'auto', aspectRatio: '1 / 1', borderRadius: 2 }} />\n ))}\n </Box>\n )\n }\n\n return (\n <Stack spacing={2} data-starter-shelf={mode}>\n {found.loading ? <LinearProgress aria-label=\"Searching starters\" /> : null}\n {found.error ? (\n <Alert\n severity=\"error\"\n action={\n <Button color=\"inherit\" size=\"small\" onClick={found.refresh}>\n {'Try again'}\n </Button>\n }\n >\n {found.error.message}\n </Alert>\n ) : options.length === 0 ? (\n <Alert\n severity=\"info\"\n action={\n <Button\n color=\"inherit\"\n size=\"small\"\n component={Link}\n href={STARTERS_HELP.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {'How starters work'}\n </Button>\n }\n >\n {emptyMessage(props)}\n </Alert>\n ) : (\n <OptionCardGrid\n label={mode === 'ai' ? 'AI starters' : 'Starters'}\n options={options}\n value={value}\n columns={{ xs: 1, sm: 2, md: 3 }}\n onChange={(listingId) => {\n const row = found.rows.find((candidate) => candidate.listingId === listingId)\n if (!row) return\n setPicked(listingId)\n const override = ownedOverride(row)\n onPick(override === undefined ? row : { ...row, owned: override })\n }}\n />\n )}\n {pickedRow && pickedRow.priceUsd > 0 ? (\n ownedOf(pickedRow, ownedOverride(pickedRow)) ? (\n <Alert severity=\"success\" data-starter-owned={pickedRow.listingId} sx={PICK_NOTE_SX}>\n {'You own this starter. Create your site from it whenever you are ready.'}\n </Alert>\n ) : purchase.panel ? (\n <Box data-starter-pay={pickedRow.listingId} sx={PAY_PANEL_SX}>\n {purchase.panel}\n </Box>\n ) : (\n <Alert\n severity=\"info\"\n data-starter-buy={pickedRow.listingId}\n sx={PICK_NOTE_SX}\n action={\n <Button\n color=\"inherit\"\n size=\"small\"\n disabled={purchase.busy || !orgId}\n onClick={() => void buy(pickedRow)}\n >\n {purchase.busy ? 'Opening…' : 'Buy and continue'}\n </Button>\n }\n >\n {`${pickedRow.displayName || 'This starter'} costs ${starterPriceLabel(pickedRow.priceUsd)}. ` +\n 'Buy it here, then create your site from it.'}\n </Alert>\n )\n ) : null}\n {purchase.error ? <Alert severity=\"error\">{purchase.error}</Alert> : null}\n {readingPicked?.failed ? (\n <Alert\n severity=\"error\"\n data-starter-answers-failed={pickedRow?.listingId}\n action={\n <Button color=\"inherit\" size=\"small\" onClick={readAgain}>\n {'Try again'}\n </Button>\n }\n >\n {readingPicked.failed}\n </Alert>\n ) : readingPicked ? (\n <LinearProgress aria-label=\"Reading this starter’s answers\" />\n ) : null}\n </Stack>\n )\n}\n\nexport default StarterPickerShelf\n"],"names":["pluginDocsHelp","resolveMediaSrc","mdiWeb","OptionCardGrid","Alert","Box","Button","Link","LinearProgress","Skeleton","Stack","useEffect","useMemo","useRef","useState","useStarterAnswers","useStarterPurchase","useStarterSearch","starterCardFacts","starterPriceLabel","PICK_NOTE_SX","position","bottom","theme","spacing","zIndex","boxShadow","PAY_PANEL_SX","p","borderRadius","bgcolor","maxHeight","overflow","STARTERS_HELP","PREVIEW_SIZE","width","height","PLACEHOLDER_CARDS","REFUSED","Set","chipOf","fact","row","key","priceUsd","label","color","variant","previewOf","src","previewImageUrl","alt","displayName","cardOf","image","id","listingId","title","authorName","description","icon","path","chips","map","narrowed","filter","some","ownedOf","override","owned","emptyMessage","props","search","trim","mode","StarterPickerShelf","found","orgId","orgSlug","onPick","ready","selected","restored","word","include","picked","setPicked","shown","setShown","ownedHere","setOwnedHere","unpaidHere","setUnpaidHere","purchase","starterAnswers","value","undefined","pickedRow","rows","find","ownedOverride","has","refused","error","status","verdict","settled","length","readyRef","current","reported","onPickRef","handedBack","pickedOwned","answersKey","facets","reading","setReading","readAttempt","setReadAttempt","askedAnswers","handed","failed","read","then","outcome","message","answers","add","readingPicked","readAgain","count","options","buy","next","delete","aria-busy","aria-label","sx","display","gap","gridTemplateColumns","xs","sm","md","Array","from","_","index","aspectRatio","data-starter-shelf","loading","severity","action","size","onClick","refresh","component","href","target","rel","columns","onChange","candidate","data-starter-owned","panel","data-starter-pay","data-starter-buy","disabled","busy","data-starter-answers-failed"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/starter-picker-shelf.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 { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { resolveMediaSrc } from '@aglyn/aglyn/app-utils/media-ref'\nimport type { SiteStarterFacets } from '@aglyn/aglyn/app-utils/site-starter'\nimport type { ConsoleHostStarterPickerZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport type { SiteStarterSummary } from '@aglyn/aglyn/plugin-manager/plugin-site-starters'\nimport { mdiWeb } from '@aglyn/shared-data-mdi'\nimport {\n OptionCardGrid,\n type OptionCard,\n type OptionCardChip,\n type OptionCardImage,\n} from '@aglyn/shared-ui-jsx/components/option-card-grid.component'\nimport { BlockedControl } from '@aglyn/shared-ui-jsx/components/blocked-control.component'\nimport {\n Alert,\n Box,\n Button,\n Link,\n LinearProgress,\n Skeleton,\n Stack,\n type SxProps,\n type Theme,\n} from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useStarterAnswers } from '../hooks/use-starter-answers'\nimport { useStarterPurchase } from '../hooks/use-starter-purchase'\nimport { useStarterSearch } from '../hooks/use-starter-search'\nimport { starterCardFacts, starterPriceLabel, type StarterCardFact } from '../model/starter-query'\n\n/**\n * What a picked starter's price or licence says, held at the foot of the\n * visible cards while the shelf is in view, so \"Buy and continue\" is beside\n * whichever card was clicked rather than below all of them.\n */\nconst PICK_NOTE_SX: SxProps<Theme> = {\n position: 'sticky',\n bottom: (theme) => theme.spacing(2),\n zIndex: 1,\n boxShadow: 3,\n}\n\n/**\n * The payment, where the note was, on its own surface. It may fill the window\n * below the app bar, so a form that has grown keeps its button on screen; a\n * smaller window scrolls inside it.\n */\nconst PAY_PANEL_SX: SxProps<Theme> = {\n position: 'sticky',\n bottom: (theme) => theme.spacing(2),\n zIndex: 1,\n boxShadow: 3,\n p: 2,\n borderRadius: 1,\n bgcolor: 'background.paper',\n maxHeight: (theme) => `calc(100dvh - ${theme.spacing(10)})`,\n overflow: 'auto',\n}\n\n/** The guide to site starters, linked from what the shelf says when it has nothing to show. */\nconst STARTERS_HELP = pluginDocsHelp('siteStarters')\n\n/**\n * A starter's preview as the card draws it: the size the platform's own\n * style previews are rendered at (square), so a row of cards stays level and\n * a publisher's picture is cropped to the same shape from its top.\n */\nconst PREVIEW_SIZE = { width: 800, height: 800 } as const\n\n/** How many placeholder cards stand in for the first answer. */\nconst PLACEHOLDER_CARDS = 3\n\n/** Statuses that mean this workspace may not have starters offered here: the dialog's own choice instead. */\nconst REFUSED = new Set([401, 403, 503])\n\n/** How each fact's chip is colored, from the theme: the price as the marketplace's own cards color it. */\nfunction chipOf(fact: StarterCardFact, row: SiteStarterSummary): OptionCardChip {\n switch (fact.key) {\n case 'price':\n return row.priceUsd > 0\n ? { label: fact.label, color: 'primary', variant: 'filled' }\n : { label: fact.label, color: 'success', variant: 'outlined' }\n case 'official':\n return { label: fact.label, color: 'primary', variant: 'outlined' }\n case 'ai':\n return { label: fact.label, color: 'secondary', variant: 'outlined' }\n default:\n return { label: fact.label }\n }\n}\n\n/** The picture a card draws, resolved the way the listing's own pages resolve it. */\nfunction previewOf(row: SiteStarterSummary): OptionCardImage | null {\n const src = resolveMediaSrc(row.previewImageUrl)\n if (!src) return null\n return { src, alt: `A preview of ${row.displayName || 'this starter'}`, ...PREVIEW_SIZE }\n}\n\n/** One starter as a card in the shared option grid. */\nfunction cardOf(row: SiteStarterSummary): OptionCard {\n const image = previewOf(row)\n return {\n id: row.listingId,\n title: row.displayName || 'Untitled starter',\n ...(row.authorName ? { description: `By ${row.authorName}` } : {}),\n ...(image ? { image } : { icon: mdiWeb.path }),\n chips: starterCardFacts(row).map((fact) => chipOf(fact, row)),\n }\n}\n\nconst narrowed = (filter: Partial<SiteStarterFacets>): boolean =>\n (['kind', 'base', 'fonts'] as const).some((key) => typeof filter[key] === 'string' && filter[key] !== '')\n\n/** A row with what the dialog or a purchase knows about owning it laid over the search's answer. */\nconst ownedOf = (row: SiteStarterSummary, override: boolean | undefined): boolean =>\n override ?? row.owned === true\n\n/** What an answer with no starters says, in the words of what was asked. */\nfunction emptyMessage(props: ConsoleHostStarterPickerZoneProps): string {\n if (props.search.trim()) return 'No starters match — try fewer words'\n if (narrowed(props.filter ?? {})) return 'No starters match these choices — try another'\n return props.mode === 'ai' ? 'No AI starters yet' : 'No starters yet'\n}\n\n/**\n * The marketplace's starters in \"Choose your starter\" (AGL-4049): the\n * `hostStarterPicker` zone, drawn before the site exists.\n *\n * Lists what the dialog asks for — its mode, its search words and its\n * filters — as cards of the shared option grid: a picture, the name, who made\n * it, and its price, kind, page count and the \"AI\" and platform marks as\n * chips. NOTHING is selected when it opens; a person picks, and the pick goes\n * to the dialog through `onPick`. It creates nothing: the dialog creates the\n * site from the starter it was handed.\n *\n * `ready` tells the dialog whether a picker is on screen. The first answer\n * decides: starters, or a search that found none (its empty state is a\n * picker with nothing in it yet), answer `true`; a workspace refused the\n * starters (no permission, the release flag off, no source) or a catalog with\n * nothing in it answers `false`, and the dialog offers its own choice\n * instead. Once shown, a later refusal hands back the same way; a later\n * failure is said here with a way to ask again.\n *\n * A picked starter with a price the workspace has not paid says so under\n * the cards, with \"Buy and continue\": the marketplace's payment, in place, on\n * the card on file, with the site still to be created. One it owns says that\n * instead. The dialog's own `selected` wins over the shelf's pick: it is how\n * a pick restored after paying is shown chosen, and how one the create\n * refused is cleared.\n *\n * An AI starter the workspace may use — free, owned, or just bought — has\n * the answers it carries read once it is picked (AGL-4049 phase 4), and\n * handed to the dialog with it (`onPick(pick, { answers })`), which goes on\n * to the AI start's questions with them. A priced one not yet bought is\n * never read: its answers are what it sells, and the door would ask payment\n * for them. A door that still asks is told back to the dialog as unowned.\n */\nexport function StarterPickerShelf(props: ConsoleHostStarterPickerZoneProps) {\n const { orgId, orgSlug, mode, search, filter, onPick, ready, selected } = props\n // The pick the dialog opened on, restored after paying for it: asked for\n // by every search from then on, so it is listed (first) wherever the\n // search would have put it, and never moves under the person's cursor.\n const [restored] = useState(() => selected?.listingId ?? null)\n const found = useStarterSearch({ orgId, mode, word: search, filter, include: restored })\n const [picked, setPicked] = useState<string | null>(null)\n const [shown, setShown] = useState(false)\n // Starters a purchase attempt found this workspace already owns.\n const [ownedHere, setOwnedHere] = useState<ReadonlySet<string>>(() => new Set())\n // AI starters whose answers the door still asked payment for (AGL-4049).\n const [unpaidHere, setUnpaidHere] = useState<ReadonlySet<string>>(() => new Set())\n const purchase = useStarterPurchase(orgId, orgSlug)\n const starterAnswers = useStarterAnswers(orgId)\n const value = selected !== undefined ? (selected?.listingId ?? null) : picked\n const pickedRow = value ? (found.rows.find((row) => row.listingId === value) ?? null) : null\n const ownedOverride = (row: SiteStarterSummary): boolean | undefined =>\n ownedHere.has(row.listingId)\n ? true\n : unpaidHere.has(row.listingId)\n ? false\n : selected?.listingId === row.listingId\n ? selected.owned\n : undefined\n\n const refused = found.error !== null && REFUSED.has(found.error.status)\n // `null` until the first answer, which is the only one that may decide\n // there is nothing to show; after that only a refusal takes it back.\n const verdict: boolean | null = !found.settled\n ? null\n : refused\n ? false\n : shown\n ? true\n : found.error\n ? false\n : found.rows.length > 0 || search.trim() !== '' || narrowed(filter ?? {})\n\n useEffect(() => {\n if (verdict === true) setShown(true)\n if (verdict === false) setShown(false)\n }, [verdict])\n\n // Each distinct verdict once, whatever identity the dialog's callback has.\n const readyRef = useRef(ready)\n readyRef.current = ready\n const reported = useRef<boolean | null>(null)\n useEffect(() => {\n if (verdict === null || reported.current === verdict) return\n reported.current = verdict\n readyRef.current(verdict)\n }, [verdict])\n\n // A pick the dialog restored is handed back once the shelf has read it,\n // so the dialog holds the starter as the search describes it.\n const onPickRef = useRef(onPick)\n onPickRef.current = onPick\n const handedBack = useRef(false)\n useEffect(() => {\n if (!restored || handedBack.current || !pickedRow || pickedRow.listingId !== restored) return\n handedBack.current = true\n const override = ownedOverride(pickedRow)\n onPickRef.current(override === undefined ? pickedRow : { ...pickedRow, owned: override })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [restored, pickedRow])\n\n // The picked AI starter's answers (AGL-4049), read once it is one the\n // workspace may use; keyed on the listing and whether it is owned, so a\n // purchase that makes it usable reads it, and nothing reads it twice.\n const pickedOwned = pickedRow ? ownedOf(pickedRow, ownedOverride(pickedRow)) : false\n const answersKey =\n pickedRow && pickedRow.facets.mode === 'ai' && (pickedRow.priceUsd <= 0 || pickedOwned)\n ? `${pickedRow.listingId}:${pickedOwned}`\n : null\n const [reading, setReading] = useState<{ key: string; failed: string | null } | null>(null)\n const [readAttempt, setReadAttempt] = useState(0)\n const askedAnswers = useRef<string | null>(null)\n useEffect(() => {\n if (!answersKey || !pickedRow || askedAnswers.current === answersKey) return\n askedAnswers.current = answersKey\n const row = pickedRow\n const override = ownedOverride(row)\n const handed = override === undefined ? row : { ...row, owned: override }\n setReading({ key: answersKey, failed: null })\n void starterAnswers.read(row.listingId).then((outcome) => {\n if (askedAnswers.current !== answersKey) return\n if (outcome.status === 'failed') return setReading({ key: answersKey, failed: outcome.message })\n setReading(null)\n if (outcome.status === 'ready') return onPickRef.current(handed, { answers: outcome.answers })\n setUnpaidHere((current) => new Set(current).add(row.listingId))\n onPickRef.current({ ...row, owned: false })\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [answersKey, readAttempt])\n const readingPicked = reading !== null && reading.key === answersKey ? reading : null\n const readAgain = () => {\n askedAnswers.current = null\n setReadAttempt((count) => count + 1)\n }\n\n const options = useMemo(() => found.rows.map(cardOf), [found.rows])\n\n const buy = async (row: SiteStarterSummary) => {\n const outcome = await purchase.buy({ listingId: row.listingId, displayName: row.displayName })\n if (outcome !== 'owned') return\n setOwnedHere((current) => new Set(current).add(row.listingId))\n setUnpaidHere((current) => {\n const next = new Set(current)\n next.delete(row.listingId)\n return next\n })\n onPick({ ...row, owned: true })\n }\n\n if (verdict === false) return null\n if (verdict === null) {\n return (\n <Box\n aria-busy\n aria-label=\"Loading starters\"\n sx={{ display: 'grid', gap: 2, gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, minmax(0, 1fr))', md: 'repeat(3, minmax(0, 1fr))' } }}\n >\n {Array.from({ length: PLACEHOLDER_CARDS }, (_, index) => (\n <Skeleton key={index} variant=\"rounded\" sx={{ height: 'auto', aspectRatio: '1 / 1', borderRadius: 2 }} />\n ))}\n </Box>\n )\n }\n\n return (\n <Stack spacing={2} data-starter-shelf={mode}>\n {found.loading ? <LinearProgress aria-label=\"Searching starters\" /> : null}\n {found.error ? (\n <Alert\n severity=\"error\"\n action={\n <Button color=\"inherit\" size=\"small\" onClick={found.refresh}>\n {'Try again'}\n </Button>\n }\n >\n {found.error.message}\n </Alert>\n ) : options.length === 0 ? (\n <Alert\n severity=\"info\"\n action={\n <Button\n color=\"inherit\"\n size=\"small\"\n component={Link}\n href={STARTERS_HELP.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {'How starters work'}\n </Button>\n }\n >\n {emptyMessage(props)}\n </Alert>\n ) : (\n <OptionCardGrid\n label={mode === 'ai' ? 'AI starters' : 'Starters'}\n options={options}\n value={value}\n columns={{ xs: 1, sm: 2, md: 3 }}\n onChange={(listingId) => {\n const row = found.rows.find((candidate) => candidate.listingId === listingId)\n if (!row) return\n setPicked(listingId)\n const override = ownedOverride(row)\n onPick(override === undefined ? row : { ...row, owned: override })\n }}\n />\n )}\n {pickedRow && pickedRow.priceUsd > 0 ? (\n ownedOf(pickedRow, ownedOverride(pickedRow)) ? (\n <Alert severity=\"success\" data-starter-owned={pickedRow.listingId} sx={PICK_NOTE_SX}>\n {'You own this starter. Create your site from it whenever you are ready.'}\n </Alert>\n ) : purchase.panel ? (\n <Box data-starter-pay={pickedRow.listingId} sx={PAY_PANEL_SX}>\n {purchase.panel}\n </Box>\n ) : (\n <Alert\n severity=\"info\"\n data-starter-buy={pickedRow.listingId}\n sx={PICK_NOTE_SX}\n action={\n <BlockedControl\n blocked={Boolean(pickedRow.buyBlockedReason)}\n reason={pickedRow.buyBlockedReason ?? ''}\n >\n <Button\n color=\"inherit\"\n size=\"small\"\n disabled={purchase.busy || !orgId}\n onClick={() => void buy(pickedRow)}\n >\n {purchase.busy ? 'Opening…' : 'Buy and continue'}\n </Button>\n </BlockedControl>\n }\n >\n {`${pickedRow.displayName || 'This starter'} costs ${starterPriceLabel(pickedRow.priceUsd)}. ` +\n (pickedRow.buyBlockedReason ?? 'Buy it here, then create your site from it.')}\n </Alert>\n )\n ) : null}\n {purchase.error ? <Alert severity=\"error\">{purchase.error}</Alert> : null}\n {readingPicked?.failed ? (\n <Alert\n severity=\"error\"\n data-starter-answers-failed={pickedRow?.listingId}\n action={\n <Button color=\"inherit\" size=\"small\" onClick={readAgain}>\n {'Try again'}\n </Button>\n }\n >\n {readingPicked.failed}\n </Alert>\n ) : readingPicked ? (\n <LinearProgress aria-label=\"Reading this starter’s answers\" />\n ) : null}\n </Stack>\n )\n}\n\nexport default StarterPickerShelf\n"],"names":["pluginDocsHelp","resolveMediaSrc","mdiWeb","OptionCardGrid","BlockedControl","Alert","Box","Button","Link","LinearProgress","Skeleton","Stack","useEffect","useMemo","useRef","useState","useStarterAnswers","useStarterPurchase","useStarterSearch","starterCardFacts","starterPriceLabel","PICK_NOTE_SX","position","bottom","theme","spacing","zIndex","boxShadow","PAY_PANEL_SX","p","borderRadius","bgcolor","maxHeight","overflow","STARTERS_HELP","PREVIEW_SIZE","width","height","PLACEHOLDER_CARDS","REFUSED","Set","chipOf","fact","row","key","priceUsd","label","color","variant","previewOf","src","previewImageUrl","alt","displayName","cardOf","image","id","listingId","title","authorName","description","icon","path","chips","map","narrowed","filter","some","ownedOf","override","owned","emptyMessage","props","search","trim","mode","StarterPickerShelf","found","pickedRow","orgId","orgSlug","onPick","ready","selected","restored","word","include","picked","setPicked","shown","setShown","ownedHere","setOwnedHere","unpaidHere","setUnpaidHere","purchase","starterAnswers","value","undefined","rows","find","ownedOverride","has","refused","error","status","verdict","settled","length","readyRef","current","reported","onPickRef","handedBack","pickedOwned","answersKey","facets","reading","setReading","readAttempt","setReadAttempt","askedAnswers","handed","failed","read","then","outcome","message","answers","add","readingPicked","readAgain","count","options","buy","next","delete","aria-busy","aria-label","sx","display","gap","gridTemplateColumns","xs","sm","md","Array","from","_","index","aspectRatio","data-starter-shelf","loading","severity","action","size","onClick","refresh","component","href","target","rel","columns","onChange","candidate","data-starter-owned","panel","data-starter-pay","data-starter-buy","blocked","Boolean","buyBlockedReason","reason","disabled","busy","data-starter-answers-failed"],"mappings":"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"}
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
18
|
* The plugin's DECLARATIONS (AGL-4047): installing into a site and publishing
|
|
19
|
-
* from one,
|
|
19
|
+
* from one, and the workspace's publisher acts (its profile, its published
|
|
20
|
+
* listings), which the one permission catalog lists beside the core keys.
|
|
20
21
|
* Loaded eagerly by the console (client and server) and the tenant's server
|
|
21
22
|
* through the generated declarations manifest, so the role editor offers
|
|
22
23
|
* them, a custom role or a per-member override keeps them, and the site's
|
package/src/lib/declarations.js
CHANGED
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { registerPluginEntitlements } from "@aglyn/aglyn/plugin-manager/plugin-entitlements";
|
|
17
|
+
import { registerPluginPermissions } from "@aglyn/aglyn/plugin-manager/plugin-permissions";
|
|
18
|
+
import { MARKETPLACE_PUBLISHER_PERMISSIONS } from "./model/marketplace-publisher-permissions.js";
|
|
17
19
|
import { MARKETPLACE_SITE_PERMISSIONS } from "./model/marketplace-site-permissions.js";
|
|
18
20
|
let declared = false;
|
|
19
21
|
/**
|
|
20
22
|
* The plugin's DECLARATIONS (AGL-4047): installing into a site and publishing
|
|
21
|
-
* from one,
|
|
23
|
+
* from one, and the workspace's publisher acts (its profile, its published
|
|
24
|
+
* listings), which the one permission catalog lists beside the core keys.
|
|
22
25
|
* Loaded eagerly by the console (client and server) and the tenant's server
|
|
23
26
|
* through the generated declarations manifest, so the role editor offers
|
|
24
27
|
* them, a custom role or a per-member override keeps them, and the site's
|
|
@@ -31,6 +34,7 @@ let declared = false;
|
|
|
31
34
|
pluginId: 'marketplace',
|
|
32
35
|
orgPermissions: MARKETPLACE_SITE_PERMISSIONS
|
|
33
36
|
});
|
|
37
|
+
registerPluginPermissions(MARKETPLACE_PUBLISHER_PERMISSIONS);
|
|
34
38
|
}
|
|
35
39
|
registerMarketplaceDeclarations();
|
|
36
40
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/declarations.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { registerPluginEntitlements } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport { MARKETPLACE_SITE_PERMISSIONS } from './model/marketplace-site-permissions'\n\nlet declared = false\n\n/**\n * The plugin's DECLARATIONS (AGL-4047): installing into a site and publishing\n * from one, which the one permission catalog lists beside the core keys.\n * Loaded eagerly by the console (client and server) and the tenant's server\n * through the generated declarations manifest, so the role editor offers\n * them, a custom role or a per-member override keeps them, and the site's\n * stamp carries them. Light by construction: nothing here reaches a\n * provider, Firestore or React.\n */\nexport function registerMarketplaceDeclarations(): void {\n if (declared) return\n declared = true\n registerPluginEntitlements({ pluginId: 'marketplace', orgPermissions: MARKETPLACE_SITE_PERMISSIONS })\n}\n\nregisterMarketplaceDeclarations()\n"],"names":["registerPluginEntitlements","MARKETPLACE_SITE_PERMISSIONS","declared","registerMarketplaceDeclarations","pluginId","orgPermissions"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,0BAA0B,QAAQ,kDAAiD;AAC5F,SAASC,4BAA4B,QAAQ,0CAAsC;AAEnF,IAAIC,WAAW;AAEf
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/declarations.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { registerPluginEntitlements } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport { registerPluginPermissions } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\nimport { MARKETPLACE_PUBLISHER_PERMISSIONS } from './model/marketplace-publisher-permissions'\nimport { MARKETPLACE_SITE_PERMISSIONS } from './model/marketplace-site-permissions'\n\nlet declared = false\n\n/**\n * The plugin's DECLARATIONS (AGL-4047): installing into a site and publishing\n * from one, and the workspace's publisher acts (its profile, its published\n * listings), which the one permission catalog lists beside the core keys.\n * Loaded eagerly by the console (client and server) and the tenant's server\n * through the generated declarations manifest, so the role editor offers\n * them, a custom role or a per-member override keeps them, and the site's\n * stamp carries them. Light by construction: nothing here reaches a\n * provider, Firestore or React.\n */\nexport function registerMarketplaceDeclarations(): void {\n if (declared) return\n declared = true\n registerPluginEntitlements({ pluginId: 'marketplace', orgPermissions: MARKETPLACE_SITE_PERMISSIONS })\n registerPluginPermissions(MARKETPLACE_PUBLISHER_PERMISSIONS)\n}\n\nregisterMarketplaceDeclarations()\n"],"names":["registerPluginEntitlements","registerPluginPermissions","MARKETPLACE_PUBLISHER_PERMISSIONS","MARKETPLACE_SITE_PERMISSIONS","declared","registerMarketplaceDeclarations","pluginId","orgPermissions"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,0BAA0B,QAAQ,kDAAiD;AAC5F,SAASC,yBAAyB,QAAQ,iDAAgD;AAC1F,SAASC,iCAAiC,QAAQ,+CAA2C;AAC7F,SAASC,4BAA4B,QAAQ,0CAAsC;AAEnF,IAAIC,WAAW;AAEf;;;;;;;;;CASC,GACD,OAAO,SAASC;IACd,IAAID,UAAU;IACdA,WAAW;IACXJ,2BAA2B;QAAEM,UAAU;QAAeC,gBAAgBJ;IAA6B;IACnGF,0BAA0BC;AAC5B;AAEAG"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
*/
|
|
17
|
+
import type { PluginPermission } from '@aglyn/aglyn/plugin-manager/plugin-permissions';
|
|
18
|
+
/** The marketplace's publisher keys. */
|
|
19
|
+
export type MarketplacePublisherPermission = 'marketplace.publisherProfile' | 'marketplace.manageListings' | 'marketplace.payouts';
|
|
20
|
+
export declare const MARKETPLACE_PUBLISHER_PROFILE_PERMISSION: MarketplacePublisherPermission;
|
|
21
|
+
export declare const MARKETPLACE_MANAGE_LISTINGS_PERMISSION: MarketplacePublisherPermission;
|
|
22
|
+
export declare const MARKETPLACE_PAYOUTS_PERMISSION: MarketplacePublisherPermission;
|
|
23
|
+
/** The keys as the plugin declares them; owners and admins hold each by default. */
|
|
24
|
+
export declare const MARKETPLACE_PUBLISHER_PERMISSIONS: readonly PluginPermission[];
|
|
25
|
+
/** The refusal a door answers without one: names the permission, never a role. */
|
|
26
|
+
export declare function marketplacePublisherPermissionRefusal(key: MarketplacePublisherPermission): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
*/ export const MARKETPLACE_PUBLISHER_PROFILE_PERMISSION = 'marketplace.publisherProfile';
|
|
17
|
+
export const MARKETPLACE_MANAGE_LISTINGS_PERMISSION = 'marketplace.manageListings';
|
|
18
|
+
export const MARKETPLACE_PAYOUTS_PERMISSION = 'marketplace.payouts';
|
|
19
|
+
/** The keys as the plugin declares them; owners and admins hold each by default. */ export const MARKETPLACE_PUBLISHER_PERMISSIONS = [
|
|
20
|
+
{
|
|
21
|
+
key: 'marketplace.publisherProfile',
|
|
22
|
+
pluginId: 'marketplace',
|
|
23
|
+
label: 'Edit the publisher profile',
|
|
24
|
+
description: 'Change the workspace’s public marketplace profile (its handle, name, bio, logo, support contact and links), and ask for the Verified publisher badge or withdraw the ask.',
|
|
25
|
+
defaults: {
|
|
26
|
+
admin: true,
|
|
27
|
+
editor: false,
|
|
28
|
+
viewer: false
|
|
29
|
+
},
|
|
30
|
+
groupLabel: 'Marketplace'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: 'marketplace.manageListings',
|
|
34
|
+
pluginId: 'marketplace',
|
|
35
|
+
label: 'Manage published listings',
|
|
36
|
+
description: 'Edit the listings the workspace has published (their words, pictures and category), make a plugin public or private, unpublish or republish a listing, and see each version’s review status.',
|
|
37
|
+
defaults: {
|
|
38
|
+
admin: true,
|
|
39
|
+
editor: false,
|
|
40
|
+
viewer: false
|
|
41
|
+
},
|
|
42
|
+
groupLabel: 'Marketplace'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: 'marketplace.payouts',
|
|
46
|
+
pluginId: 'marketplace',
|
|
47
|
+
label: 'Manage marketplace payouts',
|
|
48
|
+
description: 'Connect the payout account the workspace’s paid listings pay into, finish its setup, and open its payouts.',
|
|
49
|
+
defaults: {
|
|
50
|
+
admin: true,
|
|
51
|
+
editor: false,
|
|
52
|
+
viewer: false
|
|
53
|
+
},
|
|
54
|
+
groupLabel: 'Marketplace'
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
/** The refusal a door answers without one: names the permission, never a role. */ export function marketplacePublisherPermissionRefusal(key) {
|
|
58
|
+
var _ref;
|
|
59
|
+
var _MARKETPLACE_PUBLISHER_PERMISSIONS_find;
|
|
60
|
+
const label = (_ref = (_MARKETPLACE_PUBLISHER_PERMISSIONS_find = MARKETPLACE_PUBLISHER_PERMISSIONS.find((entry)=>entry.key === key)) == null ? void 0 : _MARKETPLACE_PUBLISHER_PERMISSIONS_find.label) != null ? _ref : key;
|
|
61
|
+
return `Your role does not include "${label}" — ask an organization admin`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=marketplace-publisher-permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/model/marketplace-publisher-permissions.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PluginPermission } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\n\n/*\n * THE WORKSPACE AS A MARKETPLACE PUBLISHER (AGL-4047).\n *\n * Saving the publisher profile, managing the listings the workspace has\n * published and setting up where its sales are paid asked whether the\n * member's workspace role was owner or admin: the routes through a role\n * helper, and the Firestore rules on `publisherProfiles` and\n * `marketplaceListings` through a role list of their own. Each is now a key\n * whose default is exactly those roles (the owner on the admin tier), so\n * nobody's access moved, and a custom role or a member's own permissions can\n * grant or refuse it.\n *\n * What is NOT a key: whether someone belongs to the workspace that published\n * a listing (`isPublisherMember`). Its members install it free on its own\n * sites (`ownsListingHere`; anywhere else they buy it like anyone), and\n * nobody in it may buy or review it. That is a fact about who published the\n * listing, so no grant can buy it and no refusal can take it away.\n *\n * Declared through `registerPluginPermissions`, as Sequences declares its own\n * workspace keys: a key of that registry rides the permission map the\n * console hands the marketplace's pages, which is what the seller sections\n * disable their controls by.\n */\n\n/** The marketplace's publisher keys. */\nexport type MarketplacePublisherPermission =\n | 'marketplace.publisherProfile'\n | 'marketplace.manageListings'\n | 'marketplace.payouts'\n\nexport const MARKETPLACE_PUBLISHER_PROFILE_PERMISSION: MarketplacePublisherPermission = 'marketplace.publisherProfile'\nexport const MARKETPLACE_MANAGE_LISTINGS_PERMISSION: MarketplacePublisherPermission = 'marketplace.manageListings'\nexport const MARKETPLACE_PAYOUTS_PERMISSION: MarketplacePublisherPermission = 'marketplace.payouts'\n\n/** The keys as the plugin declares them; owners and admins hold each by default. */\nexport const MARKETPLACE_PUBLISHER_PERMISSIONS: readonly PluginPermission[] = [\n {\n key: 'marketplace.publisherProfile',\n pluginId: 'marketplace',\n label: 'Edit the publisher profile',\n description:\n 'Change the workspace’s public marketplace profile (its handle, name, bio, logo, support contact and links), and ask for the Verified publisher badge or withdraw the ask.',\n defaults: { admin: true, editor: false, viewer: false },\n groupLabel: 'Marketplace',\n },\n {\n key: 'marketplace.manageListings',\n pluginId: 'marketplace',\n label: 'Manage published listings',\n description:\n 'Edit the listings the workspace has published (their words, pictures and category), make a plugin public or private, unpublish or republish a listing, and see each version’s review status.',\n defaults: { admin: true, editor: false, viewer: false },\n groupLabel: 'Marketplace',\n },\n {\n key: 'marketplace.payouts',\n pluginId: 'marketplace',\n label: 'Manage marketplace payouts',\n description:\n 'Connect the payout account the workspace’s paid listings pay into, finish its setup, and open its payouts.',\n defaults: { admin: true, editor: false, viewer: false },\n groupLabel: 'Marketplace',\n },\n]\n\n/** The refusal a door answers without one: names the permission, never a role. */\nexport function marketplacePublisherPermissionRefusal(key: MarketplacePublisherPermission): string {\n const label = MARKETPLACE_PUBLISHER_PERMISSIONS.find((entry) => entry.key === key)?.label ?? key\n return `Your role does not include \"${label}\" — ask an organization admin`\n}\n"],"names":["MARKETPLACE_PUBLISHER_PROFILE_PERMISSION","MARKETPLACE_MANAGE_LISTINGS_PERMISSION","MARKETPLACE_PAYOUTS_PERMISSION","MARKETPLACE_PUBLISHER_PERMISSIONS","key","pluginId","label","description","defaults","admin","editor","viewer","groupLabel","marketplacePublisherPermissionRefusal","find","entry"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAkCD,OAAO,MAAMA,2CAA2E,+BAA8B;AACtH,OAAO,MAAMC,yCAAyE,6BAA4B;AAClH,OAAO,MAAMC,iCAAiE,sBAAqB;AAEnG,kFAAkF,GAClF,OAAO,MAAMC,oCAAiE;IAC5E;QACEC,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU;YAAEC,OAAO;YAAMC,QAAQ;YAAOC,QAAQ;QAAM;QACtDC,YAAY;IACd;IACA;QACER,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU;YAAEC,OAAO;YAAMC,QAAQ;YAAOC,QAAQ;QAAM;QACtDC,YAAY;IACd;IACA;QACER,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU;YAAEC,OAAO;YAAMC,QAAQ;YAAOC,QAAQ;QAAM;QACtDC,YAAY;IACd;CACD,CAAA;AAED,gFAAgF,GAChF,OAAO,SAASC,sCAAsCT,GAAmC;;QACzED;IAAd,MAAMG,iBAAQH,0CAAAA,kCAAkCW,IAAI,CAAC,CAACC,QAAUA,MAAMX,GAAG,KAAKA,yBAAhED,wCAAsEG,KAAK,mBAAIF;IAC7F,OAAO,CAAC,4BAA4B,EAAEE,MAAM,6BAA6B,CAAC;AAC5E"}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// the browser). Neither is safe from here; the deep path has no dependencies.
|
|
24
24
|
import { isFirstPartyMediaSrc, MEDIA_REF_PREFIX } from "@aglyn/aglyn/app-utils/media-ref";
|
|
25
25
|
import { marketplaceMinPriceUsd } from "./listing-price-floor.js";
|
|
26
|
+
import { landsInPublisherWorkspace } from "./own-listing.js";
|
|
26
27
|
import { offeredPluginVersion } from "@aglyn/aglyn/app-utils/plugin-manifest";
|
|
27
28
|
// Visibility lives in core (AGL-876), for the same reason the artifact-type
|
|
28
29
|
// union and the verification policy do: the console's listing route asks the
|
|
@@ -135,7 +136,7 @@ import { ARTIFACT_TYPE_LABELS, INSTALL_TARGETS, LISTING_CATEGORIES } from "./mar
|
|
|
135
136
|
var _listing_latestVersion;
|
|
136
137
|
if (!(listing == null ? void 0 : listing.profileId) || !viewerOrgId) return false;
|
|
137
138
|
// Only the publishing org gets the fallback; everyone else is refused.
|
|
138
|
-
if (listing.profileId
|
|
139
|
+
if (!landsInPublisherWorkspace(listing.profileId, viewerOrgId)) return false;
|
|
139
140
|
// An INSTALLABLE version exists → the route serves THAT, however much newer
|
|
140
141
|
// the pending one is. Not an unreviewed install. Reading approval alone got
|
|
141
142
|
// this backwards for a revoked listing: the route would fall back to
|