@aglyn/plugins-marketplace 1.0.0-beta.291 → 1.0.0-beta.293
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-detail-editor.component.js +32 -10
- package/src/lib/components/listing-detail-editor.component.js.map +1 -1
- package/src/lib/components/listing-verification-request.component.js +32 -11
- package/src/lib/components/listing-verification-request.component.js.map +1 -1
- package/src/lib/components/org-seller-panel.component.js +121 -143
- package/src/lib/components/org-seller-panel.component.js.map +1 -1
- package/src/lib/components/publish-artifact-dialog.component.js +115 -115
- package/src/lib/components/publish-artifact-dialog.component.js.map +1 -1
- package/src/lib/components/publish-plugin-form.component.js +32 -36
- package/src/lib/components/publish-plugin-form.component.js.map +1 -1
- package/src/lib/components/publisher-agreement-checkbox.component.d.ts +56 -0
- package/src/lib/components/publisher-agreement-checkbox.component.js +121 -0
- package/src/lib/components/publisher-agreement-checkbox.component.js.map +1 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.d.ts +45 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.js +109 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.js.map +1 -0
- package/src/lib/components/publisher-agreement-summary.component.d.ts +4 -3
- package/src/lib/components/publisher-agreement-summary.component.js +4 -3
- package/src/lib/components/publisher-agreement-summary.component.js.map +1 -1
- package/src/lib/components/starter-picker-shelf.component.d.ts +29 -0
- package/src/lib/components/starter-picker-shelf.component.js +317 -0
- package/src/lib/components/starter-picker-shelf.component.js.map +1 -0
- package/src/lib/declarations.server.js +2 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-starter-purchase.d.ts +31 -0
- package/src/lib/hooks/use-starter-purchase.js +101 -0
- package/src/lib/hooks/use-starter-purchase.js.map +1 -0
- package/src/lib/hooks/use-starter-search.d.ts +42 -0
- package/src/lib/hooks/use-starter-search.js +137 -0
- package/src/lib/hooks/use-starter-search.js.map +1 -0
- package/src/lib/model/listing-visibility.d.ts +17 -9
- package/src/lib/model/listing-visibility.js +18 -32
- package/src/lib/model/listing-visibility.js.map +1 -1
- package/src/lib/model/publisher-agreement.d.ts +105 -8
- package/src/lib/model/publisher-agreement.js +131 -24
- package/src/lib/model/publisher-agreement.js.map +1 -1
- package/src/lib/model/site-starter-listing.js +4 -1
- package/src/lib/model/site-starter-listing.js.map +1 -1
- package/src/lib/model/starter-query.d.ts +159 -0
- package/src/lib/model/starter-query.js +267 -0
- package/src/lib/model/starter-query.js.map +1 -0
- package/src/lib/plugin.js +12 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/checkout.js +45 -12
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/preview-image.js +38 -8
- package/src/lib/server/preview-image.js.map +1 -1
- package/src/lib/server/publish-dataset-schema.js +27 -2
- package/src/lib/server/publish-dataset-schema.js.map +1 -1
- package/src/lib/server/publish-email-starter.js +27 -2
- package/src/lib/server/publish-email-starter.js.map +1 -1
- package/src/lib/server/publish-email-template.js +27 -2
- package/src/lib/server/publish-email-template.js.map +1 -1
- package/src/lib/server/publish-layout.js +27 -2
- package/src/lib/server/publish-layout.js.map +1 -1
- package/src/lib/server/publish-plugin.js +120 -14
- package/src/lib/server/publish-plugin.js.map +1 -1
- package/src/lib/server/publish-preconditions.d.ts +13 -9
- package/src/lib/server/publish-preconditions.js +19 -45
- package/src/lib/server/publish-preconditions.js.map +1 -1
- package/src/lib/server/publish-starter.js +27 -2
- package/src/lib/server/publish-starter.js.map +1 -1
- package/src/lib/server/publish-template.js +27 -2
- package/src/lib/server/publish-template.js.map +1 -1
- package/src/lib/server/publish-theme.js +27 -2
- package/src/lib/server/publish-theme.js.map +1 -1
- package/src/lib/server/publish.js +27 -2
- package/src/lib/server/publish.js.map +1 -1
- package/src/lib/server/publisher-agreement-acceptance.d.ts +49 -0
- package/src/lib/server/publisher-agreement-acceptance.js +97 -0
- package/src/lib/server/publisher-agreement-acceptance.js.map +1 -0
- package/src/lib/server/publisher-profile-save.js +46 -97
- package/src/lib/server/publisher-profile-save.js.map +1 -1
- package/src/lib/server/site-starter-source.js +97 -25
- package/src/lib/server/site-starter-source.js.map +1 -1
- package/src/lib/server/starters.d.ts +31 -0
- package/src/lib/server/starters.js +170 -0
- package/src/lib/server/starters.js.map +1 -0
- package/src/lib/server/verification-request.js +33 -8
- package/src/lib/server/verification-request.js.map +1 -1
- package/src/lib/server.js +14 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/components/publisher-agreement-client.d.ts +0 -48
- package/src/lib/components/publisher-agreement-client.js +0 -93
- package/src/lib/components/publisher-agreement-client.js.map +0 -1
- package/src/lib/components/publisher-agreement-dialog.component.d.ts +0 -47
- package/src/lib/components/publisher-agreement-dialog.component.js +0 -222
- package/src/lib/components/publisher-agreement-dialog.component.js.map +0 -1
- package/src/lib/components/use-publisher-agreement-gate.d.ts +0 -58
- package/src/lib/components/use-publisher-agreement-gate.js +0 -166
- package/src/lib/components/use-publisher-agreement-gate.js.map +0 -1
- package/src/lib/model/publisher-agreement-refusal.d.ts +0 -46
- package/src/lib/model/publisher-agreement-refusal.js +0 -41
- package/src/lib/model/publisher-agreement-refusal.js.map +0 -1
|
@@ -0,0 +1,109 @@
|
|
|
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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack, Typography } from "@mui/material";
|
|
19
|
+
import { useEffect, useState } from "react";
|
|
20
|
+
import { PublisherAgreementCheckbox, usePublisherAgreementConsent } from "./publisher-agreement-checkbox.component.js";
|
|
21
|
+
/**
|
|
22
|
+
* A one-click publisher change asked first, with the agreement box above its
|
|
23
|
+
* button (AGL-4105): making a listing private or public, unpublishing or
|
|
24
|
+
* republishing it. Those were menu items that saved on the click; a save in
|
|
25
|
+
* the marketplace now agrees to the Publisher Agreement first, so the click
|
|
26
|
+
* opens this, and the change is made from here.
|
|
27
|
+
*/ export function PublisherAgreementConfirmDialog(props) {
|
|
28
|
+
const { open, title, body, confirmLabel, destructive = false, onConfirm, onClose } = props;
|
|
29
|
+
const agreement = usePublisherAgreementConsent();
|
|
30
|
+
const [busy, setBusy] = useState(false);
|
|
31
|
+
const [error, setError] = useState(null);
|
|
32
|
+
const { reset } = agreement;
|
|
33
|
+
// Every opening asks again.
|
|
34
|
+
useEffect(()=>{
|
|
35
|
+
if (!open) return;
|
|
36
|
+
reset();
|
|
37
|
+
setError(null);
|
|
38
|
+
}, [
|
|
39
|
+
open,
|
|
40
|
+
reset
|
|
41
|
+
]);
|
|
42
|
+
const confirm = async ()=>{
|
|
43
|
+
if (!agreement.consent || busy) return;
|
|
44
|
+
setBusy(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
try {
|
|
47
|
+
const refused = await onConfirm(agreement.consent);
|
|
48
|
+
if (refused) return void setError(refused);
|
|
49
|
+
reset();
|
|
50
|
+
onClose();
|
|
51
|
+
} finally{
|
|
52
|
+
setBusy(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
56
|
+
open: open,
|
|
57
|
+
onClose: busy ? undefined : onClose,
|
|
58
|
+
maxWidth: "xs",
|
|
59
|
+
fullWidth: true,
|
|
60
|
+
children: [
|
|
61
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
62
|
+
children: title
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ _jsx(DialogContent, {
|
|
65
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
66
|
+
spacing: 2,
|
|
67
|
+
children: [
|
|
68
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
69
|
+
variant: "body2",
|
|
70
|
+
color: "text.secondary",
|
|
71
|
+
children: body
|
|
72
|
+
}),
|
|
73
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
74
|
+
severity: "error",
|
|
75
|
+
children: error
|
|
76
|
+
}) : null,
|
|
77
|
+
/*#__PURE__*/ _jsx(PublisherAgreementCheckbox, {
|
|
78
|
+
checked: agreement.agreed,
|
|
79
|
+
onChange: agreement.setAgreed,
|
|
80
|
+
disabled: busy
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
}),
|
|
85
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
86
|
+
children: [
|
|
87
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
88
|
+
size: "small",
|
|
89
|
+
onClick: onClose,
|
|
90
|
+
disabled: busy,
|
|
91
|
+
children: 'Cancel'
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
94
|
+
size: "small",
|
|
95
|
+
variant: "contained",
|
|
96
|
+
color: destructive ? 'error' : 'primary',
|
|
97
|
+
disabled: busy || !agreement.agreed,
|
|
98
|
+
onClick: ()=>void confirm(),
|
|
99
|
+
children: busy ? 'Saving…' : confirmLabel
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
})
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
PublisherAgreementConfirmDialog.displayName = 'PublisherAgreementConfirmDialog';
|
|
107
|
+
export default PublisherAgreementConfirmDialog;
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=publisher-agreement-confirm-dialog.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publisher-agreement-confirm-dialog.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\n'use client'\n\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport type { PublisherAgreementConsent } from '../model/publisher-agreement'\nimport {\n PublisherAgreementCheckbox,\n usePublisherAgreementConsent,\n} from './publisher-agreement-checkbox.component'\n\nexport interface PublisherAgreementConfirmDialogProps {\n open: boolean\n title: string\n /** What the change does, in a sentence. */\n body: string\n confirmLabel: string\n /** In the error color: it takes a listing out of the marketplace. */\n destructive?: boolean\n /**\n * Makes the change with the agreement. Resolves to null when it went\n * through, which closes the dialog, or to the message to show when it was\n * refused, which keeps it open.\n */\n onConfirm: (consent: PublisherAgreementConsent) => Promise<string | null>\n onClose: () => void\n}\n\n/**\n * A one-click publisher change asked first, with the agreement box above its\n * button (AGL-4105): making a listing private or public, unpublishing or\n * republishing it. Those were menu items that saved on the click; a save in\n * the marketplace now agrees to the Publisher Agreement first, so the click\n * opens this, and the change is made from here.\n */\nexport function PublisherAgreementConfirmDialog(\n props: PublisherAgreementConfirmDialogProps,\n) {\n const { open, title, body, confirmLabel, destructive = false, onConfirm, onClose } = props\n const agreement = usePublisherAgreementConsent()\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const { reset } = agreement\n\n // Every opening asks again.\n useEffect(() => {\n if (!open) return\n reset()\n setError(null)\n }, [open, reset])\n\n const confirm = async () => {\n if (!agreement.consent || busy) return\n setBusy(true)\n setError(null)\n try {\n const refused = await onConfirm(agreement.consent)\n if (refused) return void setError(refused)\n reset()\n onClose()\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Dialog open={open} onClose={busy ? undefined : onClose} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{title}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {body}\n </Typography>\n {error ? <Alert severity=\"error\">{error}</Alert> : null}\n <PublisherAgreementCheckbox\n checked={agreement.agreed}\n onChange={agreement.setAgreed}\n disabled={busy}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n color={destructive ? 'error' : 'primary'}\n disabled={busy || !agreement.agreed}\n onClick={() => void confirm()}\n >\n {busy ? 'Saving…' : confirmLabel}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nPublisherAgreementConfirmDialog.displayName = 'PublisherAgreementConfirmDialog'\n\nexport default PublisherAgreementConfirmDialog\n"],"names":["Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","Typography","useEffect","useState","PublisherAgreementCheckbox","usePublisherAgreementConsent","PublisherAgreementConfirmDialog","props","open","title","body","confirmLabel","destructive","onConfirm","onClose","agreement","busy","setBusy","error","setError","reset","confirm","consent","refused","undefined","maxWidth","fullWidth","spacing","variant","color","severity","checked","agreed","onChange","setAgreed","disabled","size","onClick","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;AAEA,SACEA,KAAK,EACLC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,KAAK,EACLC,UAAU,QACL,gBAAe;AACtB,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAE3C,SACEC,0BAA0B,EAC1BC,4BAA4B,QACvB,8CAA0C;AAmBjD;;;;;;CAMC,GACD,OAAO,SAASC,gCACdC,KAA2C;IAE3C,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAEC,IAAI,EAAEC,YAAY,EAAEC,cAAc,KAAK,EAAEC,SAAS,EAAEC,OAAO,EAAE,GAAGP;IACrF,MAAMQ,YAAYV;IAClB,MAAM,CAACW,MAAMC,QAAQ,GAAGd,SAAS;IACjC,MAAM,CAACe,OAAOC,SAAS,GAAGhB,SAAwB;IAClD,MAAM,EAAEiB,KAAK,EAAE,GAAGL;IAElB,4BAA4B;IAC5Bb,UAAU;QACR,IAAI,CAACM,MAAM;QACXY;QACAD,SAAS;IACX,GAAG;QAACX;QAAMY;KAAM;IAEhB,MAAMC,UAAU;QACd,IAAI,CAACN,UAAUO,OAAO,IAAIN,MAAM;QAChCC,QAAQ;QACRE,SAAS;QACT,IAAI;YACF,MAAMI,UAAU,MAAMV,UAAUE,UAAUO,OAAO;YACjD,IAAIC,SAAS,OAAO,KAAKJ,SAASI;YAClCH;YACAN;QACF,SAAU;YACRG,QAAQ;QACV;IACF;IAEA,qBACE,MAACrB;QAAOY,MAAMA;QAAMM,SAASE,OAAOQ,YAAYV;QAASW,UAAS;QAAKC,SAAS;;0BAC9E,KAAC3B;0BAAaU;;0BACd,KAACX;0BACC,cAAA,MAACE;oBAAM2B,SAAS;;sCACd,KAAC1B;4BAAW2B,SAAQ;4BAAQC,OAAM;sCAC/BnB;;wBAEFQ,sBAAQ,KAACxB;4BAAMoC,UAAS;sCAASZ;6BAAiB;sCACnD,KAACd;4BACC2B,SAAShB,UAAUiB,MAAM;4BACzBC,UAAUlB,UAAUmB,SAAS;4BAC7BC,UAAUnB;;;;;0BAIhB,MAACnB;;kCACC,KAACF;wBAAOyC,MAAK;wBAAQC,SAASvB;wBAASqB,UAAUnB;kCAC9C;;kCAEH,KAACrB;wBACCyC,MAAK;wBACLR,SAAQ;wBACRC,OAAOjB,cAAc,UAAU;wBAC/BuB,UAAUnB,QAAQ,CAACD,UAAUiB,MAAM;wBACnCK,SAAS,IAAM,KAAKhB;kCAEnBL,OAAO,YAAYL;;;;;;AAK9B;AAEAL,gCAAgCgC,WAAW,GAAG;AAE9C,eAAehC,gCAA+B"}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* What the agreement commits a publisher to, and where to read all of it
|
|
3
3
|
* (AGL-1077).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Rendered on the Publisher Profile card, beside the note of when the
|
|
6
|
+
* organization last agreed. Since AGL-4105 every publisher save agrees to the
|
|
7
|
+
* agreement with its own box (`PublisherAgreementCheckbox`), so this is what
|
|
8
|
+
* that box links to, in short, and asks for nothing itself.
|
|
8
9
|
*
|
|
9
10
|
* @param documentUrl the page to link, from `publisherAgreementPresentation`
|
|
10
11
|
* and never from the constant: while the document is unpublished that
|
|
@@ -21,9 +21,10 @@ import { Link, Stack, Typography } from "@mui/material";
|
|
|
21
21
|
* What the agreement commits a publisher to, and where to read all of it
|
|
22
22
|
* (AGL-1077).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Rendered on the Publisher Profile card, beside the note of when the
|
|
25
|
+
* organization last agreed. Since AGL-4105 every publisher save agrees to the
|
|
26
|
+
* agreement with its own box (`PublisherAgreementCheckbox`), so this is what
|
|
27
|
+
* that box links to, in short, and asks for nothing itself.
|
|
27
28
|
*
|
|
28
29
|
* @param documentUrl the page to link, from `publisherAgreementPresentation`
|
|
29
30
|
* and never from the constant: while the document is unpublished that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publisher-agreement-summary.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 PUBLISHER_AGREEMENT_POINTS,\n PUBLISHER_AGREEMENT_TITLE,\n PUBLISHER_AGREEMENT_VERSION,\n} from '../model/publisher-agreement'\nimport { Link, Stack, Typography } from '@mui/material'\n\n/**\n * What the agreement commits a publisher to, and where to read all of it\n * (AGL-1077).\n *\n *
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publisher-agreement-summary.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 PUBLISHER_AGREEMENT_POINTS,\n PUBLISHER_AGREEMENT_TITLE,\n PUBLISHER_AGREEMENT_VERSION,\n} from '../model/publisher-agreement'\nimport { Link, Stack, Typography } from '@mui/material'\n\n/**\n * What the agreement commits a publisher to, and where to read all of it\n * (AGL-1077).\n *\n * Rendered on the Publisher Profile card, beside the note of when the\n * organization last agreed. Since AGL-4105 every publisher save agrees to the\n * agreement with its own box (`PublisherAgreementCheckbox`), so this is what\n * that box links to, in short, and asks for nothing itself.\n *\n * @param documentUrl the page to link, from `publisherAgreementPresentation`\n * and never from the constant: while the document is unpublished that\n * helper hands back null and there is nothing here to click. A link to a\n * 404 above an Accept button is how a publisher ends up having \"read\" a\n * document that was never served (AGL-1660).\n */\nexport function PublisherAgreementSummary(props: {\n documentUrl: string | null\n}) {\n const { documentUrl } = props\n return (\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'In summary — this is not the agreement, it is what tends to ' +\n 'surprise people later:'}\n </Typography>\n <Stack spacing={1} component=\"ul\" sx={{ m: 0, pl: 0, listStyle: 'none' }}>\n {PUBLISHER_AGREEMENT_POINTS.map((point) => (\n <Stack key={point.id} spacing={0.25} component=\"li\">\n <Typography variant=\"body2\">{point.label}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {point.detail}\n </Typography>\n </Stack>\n ))}\n </Stack>\n {documentUrl ? (\n <Typography variant=\"body2\">\n <Link\n href={documentUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n underline=\"always\"\n >\n {`Read the full ${PUBLISHER_AGREEMENT_TITLE}`}\n </Link>\n {` (version ${PUBLISHER_AGREEMENT_VERSION})`}\n </Typography>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Version ${PUBLISHER_AGREEMENT_VERSION} has no published page ` +\n 'yet, so there is no full text to link to.'}\n </Typography>\n )}\n </Stack>\n )\n}\n\nPublisherAgreementSummary.displayName = 'PublisherAgreementSummary'\n\nexport default PublisherAgreementSummary\n"],"names":["PUBLISHER_AGREEMENT_POINTS","PUBLISHER_AGREEMENT_TITLE","PUBLISHER_AGREEMENT_VERSION","Link","Stack","Typography","PublisherAgreementSummary","props","documentUrl","spacing","variant","color","component","sx","m","pl","listStyle","map","point","label","detail","id","href","target","rel","underline","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SACEA,0BAA0B,EAC1BC,yBAAyB,EACzBC,2BAA2B,QACtB,kCAA8B;AACrC,SAASC,IAAI,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AAEvD;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,0BAA0BC,KAEzC;IACC,MAAM,EAAEC,WAAW,EAAE,GAAGD;IACxB,qBACE,MAACH;QAAMK,SAAS;;0BACd,KAACJ;gBAAWK,SAAQ;gBAAQC,OAAM;0BAC/B,iEACC;;0BAEJ,KAACP;gBAAMK,SAAS;gBAAGG,WAAU;gBAAKC,IAAI;oBAAEC,GAAG;oBAAGC,IAAI;oBAAGC,WAAW;gBAAO;0BACpEhB,2BAA2BiB,GAAG,CAAC,CAACC,sBAC/B,MAACd;wBAAqBK,SAAS;wBAAMG,WAAU;;0CAC7C,KAACP;gCAAWK,SAAQ;0CAASQ,MAAMC,KAAK;;0CACxC,KAACd;gCAAWK,SAAQ;gCAAUC,OAAM;0CACjCO,MAAME,MAAM;;;uBAHLF,MAAMG,EAAE;;YAQvBb,4BACC,MAACH;gBAAWK,SAAQ;;kCAClB,KAACP;wBACCmB,MAAMd;wBACNe,QAAO;wBACPC,KAAI;wBACJC,WAAU;kCAET,CAAC,cAAc,EAAExB,2BAA2B;;oBAE9C,CAAC,UAAU,EAAEC,4BAA4B,CAAC,CAAC;;+BAG9C,KAACG;gBAAWK,SAAQ;gBAAQC,OAAM;0BAC/B,CAAC,QAAQ,EAAET,4BAA4B,uBAAuB,CAAC,GAC9D;;;;AAKZ;AAEAI,0BAA0BoB,WAAW,GAAG;AAExC,eAAepB,0BAAyB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ConsoleHostStarterPickerZoneProps } from '@aglyn/aglyn/plugin-manager/feature-plugins';
|
|
2
|
+
/**
|
|
3
|
+
* The marketplace's starters in "Choose your starter" (AGL-4049): the
|
|
4
|
+
* `hostStarterPicker` zone, drawn before the site exists.
|
|
5
|
+
*
|
|
6
|
+
* Lists what the dialog asks for — its mode, its search words and its
|
|
7
|
+
* filters — as cards of the shared option grid: a picture, the name, who made
|
|
8
|
+
* it, and its price, kind, page count and the "AI" and platform marks as
|
|
9
|
+
* chips. NOTHING is selected when it opens; a person picks, and the pick goes
|
|
10
|
+
* to the dialog through `onPick`. It creates nothing: the dialog creates the
|
|
11
|
+
* site from the starter it was handed.
|
|
12
|
+
*
|
|
13
|
+
* `ready` tells the dialog whether a picker is on screen. The first answer
|
|
14
|
+
* decides: starters, or a search that found none (its empty state is a
|
|
15
|
+
* picker with nothing in it yet), answer `true`; a workspace refused the
|
|
16
|
+
* starters (no permission, the release flag off, no source) or a catalog with
|
|
17
|
+
* nothing in it answers `false`, and the dialog offers its own choice
|
|
18
|
+
* instead. Once shown, a later refusal hands back the same way; a later
|
|
19
|
+
* failure is said here with a way to ask again.
|
|
20
|
+
*
|
|
21
|
+
* A picked starter with a price the workspace has not paid says so under
|
|
22
|
+
* the cards, with "Buy and continue": the marketplace's payment, which brings
|
|
23
|
+
* the person back to Create site on the same pick. One it owns says that
|
|
24
|
+
* instead. The dialog's own `selected` wins over the shelf's pick: it is how
|
|
25
|
+
* a pick restored after paying is shown chosen, and how one the create
|
|
26
|
+
* refused is cleared.
|
|
27
|
+
*/
|
|
28
|
+
export declare function StarterPickerShelf(props: ConsoleHostStarterPickerZoneProps): import("react").JSX.Element;
|
|
29
|
+
export default StarterPickerShelf;
|
|
@@ -0,0 +1,317 @@
|
|
|
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, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { pluginDocsHelp } from "@aglyn/aglyn/app-utils/docs-help";
|
|
20
|
+
import { resolveMediaSrc } from "@aglyn/aglyn/app-utils/media-ref";
|
|
21
|
+
import { mdiWeb } from "@aglyn/shared-data-mdi";
|
|
22
|
+
import { OptionCardGrid } from "@aglyn/shared-ui-jsx/components/option-card-grid.component";
|
|
23
|
+
import { Alert, Box, Button, Link, LinearProgress, Skeleton, Stack } from "@mui/material";
|
|
24
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
25
|
+
import { useStarterPurchase } from "../hooks/use-starter-purchase.js";
|
|
26
|
+
import { useStarterSearch } from "../hooks/use-starter-search.js";
|
|
27
|
+
import { starterCardFacts, starterPriceLabel } from "../model/starter-query.js";
|
|
28
|
+
/**
|
|
29
|
+
* What a picked starter's price or licence says, held at the foot of the
|
|
30
|
+
* visible cards while the shelf is in view, so "Buy and continue" is beside
|
|
31
|
+
* whichever card was clicked rather than below all of them.
|
|
32
|
+
*/ const PICK_NOTE_SX = {
|
|
33
|
+
position: 'sticky',
|
|
34
|
+
bottom: (theme)=>theme.spacing(2),
|
|
35
|
+
zIndex: 1,
|
|
36
|
+
boxShadow: 3
|
|
37
|
+
};
|
|
38
|
+
/** The guide to site starters, linked from what the shelf says when it has nothing to show. */ const STARTERS_HELP = pluginDocsHelp('siteStarters');
|
|
39
|
+
/**
|
|
40
|
+
* A starter's preview as the card draws it: the size the platform's own
|
|
41
|
+
* style previews are rendered at (square), so a row of cards stays level and
|
|
42
|
+
* a publisher's picture is cropped to the same shape from its top.
|
|
43
|
+
*/ const PREVIEW_SIZE = {
|
|
44
|
+
width: 800,
|
|
45
|
+
height: 800
|
|
46
|
+
};
|
|
47
|
+
/** How many placeholder cards stand in for the first answer. */ const PLACEHOLDER_CARDS = 3;
|
|
48
|
+
/** Statuses that mean this workspace may not have starters offered here: the dialog's own choice instead. */ const REFUSED = new Set([
|
|
49
|
+
401,
|
|
50
|
+
403,
|
|
51
|
+
503
|
|
52
|
+
]);
|
|
53
|
+
/** How each fact's chip is colored, from the theme: the price as the marketplace's own cards color it. */ function chipOf(fact, row) {
|
|
54
|
+
switch(fact.key){
|
|
55
|
+
case 'price':
|
|
56
|
+
return row.priceUsd > 0 ? {
|
|
57
|
+
label: fact.label,
|
|
58
|
+
color: 'primary',
|
|
59
|
+
variant: 'filled'
|
|
60
|
+
} : {
|
|
61
|
+
label: fact.label,
|
|
62
|
+
color: 'success',
|
|
63
|
+
variant: 'outlined'
|
|
64
|
+
};
|
|
65
|
+
case 'official':
|
|
66
|
+
return {
|
|
67
|
+
label: fact.label,
|
|
68
|
+
color: 'primary',
|
|
69
|
+
variant: 'outlined'
|
|
70
|
+
};
|
|
71
|
+
case 'ai':
|
|
72
|
+
return {
|
|
73
|
+
label: fact.label,
|
|
74
|
+
color: 'secondary',
|
|
75
|
+
variant: 'outlined'
|
|
76
|
+
};
|
|
77
|
+
default:
|
|
78
|
+
return {
|
|
79
|
+
label: fact.label
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** The picture a card draws, resolved the way the listing's own pages resolve it. */ function previewOf(row) {
|
|
84
|
+
const src = resolveMediaSrc(row.previewImageUrl);
|
|
85
|
+
if (!src) return null;
|
|
86
|
+
return _extends({
|
|
87
|
+
src,
|
|
88
|
+
alt: `A preview of ${row.displayName || 'this starter'}`
|
|
89
|
+
}, PREVIEW_SIZE);
|
|
90
|
+
}
|
|
91
|
+
/** One starter as a card in the shared option grid. */ function cardOf(row) {
|
|
92
|
+
const image = previewOf(row);
|
|
93
|
+
return _extends({
|
|
94
|
+
id: row.listingId,
|
|
95
|
+
title: row.displayName || 'Untitled starter'
|
|
96
|
+
}, row.authorName ? {
|
|
97
|
+
description: `By ${row.authorName}`
|
|
98
|
+
} : {}, image ? {
|
|
99
|
+
image
|
|
100
|
+
} : {
|
|
101
|
+
icon: mdiWeb.path
|
|
102
|
+
}, {
|
|
103
|
+
chips: starterCardFacts(row).map((fact)=>chipOf(fact, row))
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const narrowed = (filter)=>[
|
|
107
|
+
'kind',
|
|
108
|
+
'base',
|
|
109
|
+
'fonts'
|
|
110
|
+
].some((key)=>typeof filter[key] === 'string' && filter[key] !== '');
|
|
111
|
+
/** A row with what the dialog or a purchase knows about owning it laid over the search's answer. */ const ownedOf = (row, override)=>override != null ? override : row.owned === true;
|
|
112
|
+
/** What an answer with no starters says, in the words of what was asked. */ function emptyMessage(props) {
|
|
113
|
+
var _props_filter;
|
|
114
|
+
if (props.search.trim()) return 'No starters match — try fewer words';
|
|
115
|
+
if (narrowed((_props_filter = props.filter) != null ? _props_filter : {})) return 'No starters match these choices — try another';
|
|
116
|
+
return props.mode === 'ai' ? 'No AI starters yet' : 'No starters yet';
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The marketplace's starters in "Choose your starter" (AGL-4049): the
|
|
120
|
+
* `hostStarterPicker` zone, drawn before the site exists.
|
|
121
|
+
*
|
|
122
|
+
* Lists what the dialog asks for — its mode, its search words and its
|
|
123
|
+
* filters — as cards of the shared option grid: a picture, the name, who made
|
|
124
|
+
* it, and its price, kind, page count and the "AI" and platform marks as
|
|
125
|
+
* chips. NOTHING is selected when it opens; a person picks, and the pick goes
|
|
126
|
+
* to the dialog through `onPick`. It creates nothing: the dialog creates the
|
|
127
|
+
* site from the starter it was handed.
|
|
128
|
+
*
|
|
129
|
+
* `ready` tells the dialog whether a picker is on screen. The first answer
|
|
130
|
+
* decides: starters, or a search that found none (its empty state is a
|
|
131
|
+
* picker with nothing in it yet), answer `true`; a workspace refused the
|
|
132
|
+
* starters (no permission, the release flag off, no source) or a catalog with
|
|
133
|
+
* nothing in it answers `false`, and the dialog offers its own choice
|
|
134
|
+
* instead. Once shown, a later refusal hands back the same way; a later
|
|
135
|
+
* failure is said here with a way to ask again.
|
|
136
|
+
*
|
|
137
|
+
* A picked starter with a price the workspace has not paid says so under
|
|
138
|
+
* the cards, with "Buy and continue": the marketplace's payment, which brings
|
|
139
|
+
* the person back to Create site on the same pick. One it owns says that
|
|
140
|
+
* instead. The dialog's own `selected` wins over the shelf's pick: it is how
|
|
141
|
+
* a pick restored after paying is shown chosen, and how one the create
|
|
142
|
+
* refused is cleared.
|
|
143
|
+
*/ export function StarterPickerShelf(props) {
|
|
144
|
+
var _ref, _found_rows_find;
|
|
145
|
+
const { orgId, mode, search, filter, onPick, ready, selected } = props;
|
|
146
|
+
// The pick the dialog opened on, restored after paying for it: asked for
|
|
147
|
+
// by every search from then on, so it is listed (first) wherever the
|
|
148
|
+
// search would have put it, and never moves under the person's cursor.
|
|
149
|
+
const [restored] = useState(()=>{
|
|
150
|
+
var _ref;
|
|
151
|
+
return (_ref = selected == null ? void 0 : selected.listingId) != null ? _ref : null;
|
|
152
|
+
});
|
|
153
|
+
const found = useStarterSearch({
|
|
154
|
+
orgId,
|
|
155
|
+
mode,
|
|
156
|
+
word: search,
|
|
157
|
+
filter,
|
|
158
|
+
include: restored
|
|
159
|
+
});
|
|
160
|
+
const [picked, setPicked] = useState(null);
|
|
161
|
+
const [shown, setShown] = useState(false);
|
|
162
|
+
// Starters a purchase attempt found this workspace already owns.
|
|
163
|
+
const [ownedHere, setOwnedHere] = useState(()=>new Set());
|
|
164
|
+
const purchase = useStarterPurchase(orgId);
|
|
165
|
+
const value = selected !== undefined ? (_ref = selected == null ? void 0 : selected.listingId) != null ? _ref : null : picked;
|
|
166
|
+
const pickedRow = value ? (_found_rows_find = found.rows.find((row)=>row.listingId === value)) != null ? _found_rows_find : null : null;
|
|
167
|
+
const ownedOverride = (row)=>ownedHere.has(row.listingId) ? true : (selected == null ? void 0 : selected.listingId) === row.listingId ? selected.owned : undefined;
|
|
168
|
+
const refused = found.error !== null && REFUSED.has(found.error.status);
|
|
169
|
+
// `null` until the first answer, which is the only one that may decide
|
|
170
|
+
// there is nothing to show; after that only a refusal takes it back.
|
|
171
|
+
const verdict = !found.settled ? null : refused ? false : shown ? true : found.error ? false : found.rows.length > 0 || search.trim() !== '' || narrowed(filter != null ? filter : {});
|
|
172
|
+
useEffect(()=>{
|
|
173
|
+
if (verdict === true) setShown(true);
|
|
174
|
+
if (verdict === false) setShown(false);
|
|
175
|
+
}, [
|
|
176
|
+
verdict
|
|
177
|
+
]);
|
|
178
|
+
// Each distinct verdict once, whatever identity the dialog's callback has.
|
|
179
|
+
const readyRef = useRef(ready);
|
|
180
|
+
readyRef.current = ready;
|
|
181
|
+
const reported = useRef(null);
|
|
182
|
+
useEffect(()=>{
|
|
183
|
+
if (verdict === null || reported.current === verdict) return;
|
|
184
|
+
reported.current = verdict;
|
|
185
|
+
readyRef.current(verdict);
|
|
186
|
+
}, [
|
|
187
|
+
verdict
|
|
188
|
+
]);
|
|
189
|
+
// A pick the dialog restored is handed back once the shelf has read it,
|
|
190
|
+
// so the dialog holds the starter as the search describes it.
|
|
191
|
+
const onPickRef = useRef(onPick);
|
|
192
|
+
onPickRef.current = onPick;
|
|
193
|
+
const handedBack = useRef(false);
|
|
194
|
+
useEffect(()=>{
|
|
195
|
+
if (!restored || handedBack.current || !pickedRow || pickedRow.listingId !== restored) return;
|
|
196
|
+
handedBack.current = true;
|
|
197
|
+
const override = ownedOverride(pickedRow);
|
|
198
|
+
onPickRef.current(override === undefined ? pickedRow : _extends({}, pickedRow, {
|
|
199
|
+
owned: override
|
|
200
|
+
}));
|
|
201
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
202
|
+
}, [
|
|
203
|
+
restored,
|
|
204
|
+
pickedRow
|
|
205
|
+
]);
|
|
206
|
+
const options = useMemo(()=>found.rows.map(cardOf), [
|
|
207
|
+
found.rows
|
|
208
|
+
]);
|
|
209
|
+
const buy = async (row)=>{
|
|
210
|
+
const outcome = await purchase.buy(row.listingId);
|
|
211
|
+
if (outcome !== 'owned') return;
|
|
212
|
+
setOwnedHere((current)=>new Set(current).add(row.listingId));
|
|
213
|
+
onPick(_extends({}, row, {
|
|
214
|
+
owned: true
|
|
215
|
+
}));
|
|
216
|
+
};
|
|
217
|
+
if (verdict === false) return null;
|
|
218
|
+
if (verdict === null) {
|
|
219
|
+
return /*#__PURE__*/ _jsx(Box, {
|
|
220
|
+
"aria-busy": true,
|
|
221
|
+
"aria-label": "Loading starters",
|
|
222
|
+
sx: {
|
|
223
|
+
display: 'grid',
|
|
224
|
+
gap: 2,
|
|
225
|
+
gridTemplateColumns: {
|
|
226
|
+
xs: '1fr',
|
|
227
|
+
sm: 'repeat(2, minmax(0, 1fr))',
|
|
228
|
+
md: 'repeat(3, minmax(0, 1fr))'
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
children: Array.from({
|
|
232
|
+
length: PLACEHOLDER_CARDS
|
|
233
|
+
}, (_, index)=>/*#__PURE__*/ _jsx(Skeleton, {
|
|
234
|
+
variant: "rounded",
|
|
235
|
+
sx: {
|
|
236
|
+
height: 'auto',
|
|
237
|
+
aspectRatio: '1 / 1',
|
|
238
|
+
borderRadius: 2
|
|
239
|
+
}
|
|
240
|
+
}, index))
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
244
|
+
spacing: 2,
|
|
245
|
+
"data-starter-shelf": mode,
|
|
246
|
+
children: [
|
|
247
|
+
found.loading ? /*#__PURE__*/ _jsx(LinearProgress, {
|
|
248
|
+
"aria-label": "Searching starters"
|
|
249
|
+
}) : null,
|
|
250
|
+
found.error ? /*#__PURE__*/ _jsx(Alert, {
|
|
251
|
+
severity: "error",
|
|
252
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
253
|
+
color: "inherit",
|
|
254
|
+
size: "small",
|
|
255
|
+
onClick: found.refresh,
|
|
256
|
+
children: 'Try again'
|
|
257
|
+
}),
|
|
258
|
+
children: found.error.message
|
|
259
|
+
}) : options.length === 0 ? /*#__PURE__*/ _jsx(Alert, {
|
|
260
|
+
severity: "info",
|
|
261
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
262
|
+
color: "inherit",
|
|
263
|
+
size: "small",
|
|
264
|
+
component: Link,
|
|
265
|
+
href: STARTERS_HELP.href,
|
|
266
|
+
target: "_blank",
|
|
267
|
+
rel: "noopener noreferrer",
|
|
268
|
+
children: 'How starters work'
|
|
269
|
+
}),
|
|
270
|
+
children: emptyMessage(props)
|
|
271
|
+
}) : /*#__PURE__*/ _jsx(OptionCardGrid, {
|
|
272
|
+
label: mode === 'ai' ? 'AI starters' : 'Starters',
|
|
273
|
+
options: options,
|
|
274
|
+
value: value,
|
|
275
|
+
columns: {
|
|
276
|
+
xs: 1,
|
|
277
|
+
sm: 2,
|
|
278
|
+
md: 3
|
|
279
|
+
},
|
|
280
|
+
onChange: (listingId)=>{
|
|
281
|
+
const row = found.rows.find((candidate)=>candidate.listingId === listingId);
|
|
282
|
+
if (!row) return;
|
|
283
|
+
setPicked(listingId);
|
|
284
|
+
const override = ownedOverride(row);
|
|
285
|
+
onPick(override === undefined ? row : _extends({}, row, {
|
|
286
|
+
owned: override
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
}),
|
|
290
|
+
pickedRow && pickedRow.priceUsd > 0 ? ownedOf(pickedRow, ownedOverride(pickedRow)) ? /*#__PURE__*/ _jsx(Alert, {
|
|
291
|
+
severity: "success",
|
|
292
|
+
"data-starter-owned": pickedRow.listingId,
|
|
293
|
+
sx: PICK_NOTE_SX,
|
|
294
|
+
children: 'You own this starter. Create your site from it whenever you are ready.'
|
|
295
|
+
}) : /*#__PURE__*/ _jsx(Alert, {
|
|
296
|
+
severity: "info",
|
|
297
|
+
"data-starter-buy": pickedRow.listingId,
|
|
298
|
+
sx: PICK_NOTE_SX,
|
|
299
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
300
|
+
color: "inherit",
|
|
301
|
+
size: "small",
|
|
302
|
+
disabled: purchase.busy || !orgId,
|
|
303
|
+
onClick: ()=>void buy(pickedRow),
|
|
304
|
+
children: purchase.busy ? 'Opening…' : 'Buy and continue'
|
|
305
|
+
}),
|
|
306
|
+
children: `${pickedRow.displayName || 'This starter'} costs ${starterPriceLabel(pickedRow.priceUsd)}. ` + 'Buy it first; once paid, you come back here to create your site from it.'
|
|
307
|
+
}) : null,
|
|
308
|
+
purchase.error ? /*#__PURE__*/ _jsx(Alert, {
|
|
309
|
+
severity: "error",
|
|
310
|
+
children: purchase.error
|
|
311
|
+
}) : null
|
|
312
|
+
]
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
export default StarterPickerShelf;
|
|
316
|
+
|
|
317
|
+
//# sourceMappingURL=starter-picker-shelf.component.js.map
|
|
@@ -0,0 +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 { 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/** 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, which brings\n * the person back to Create site on the same pick. 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 */\nexport function StarterPickerShelf(props: ConsoleHostStarterPickerZoneProps) {\n const { orgId, 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 const purchase = useStarterPurchase(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) ? true : selected?.listingId === row.listingId ? selected.owned : 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 const options = useMemo(() => found.rows.map(cardOf), [found.rows])\n\n const buy = async (row: SiteStarterSummary) => {\n const outcome = await purchase.buy(row.listingId)\n if (outcome !== 'owned') return\n setOwnedHere((current) => new Set(current).add(row.listingId))\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 ) : (\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 first; once paid, you come back here to create your site from it.'}\n </Alert>\n )\n ) : null}\n {purchase.error ? <Alert severity=\"error\">{purchase.error}</Alert> : 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","useStarterPurchase","useStarterSearch","starterCardFacts","starterPriceLabel","PICK_NOTE_SX","position","bottom","theme","spacing","zIndex","boxShadow","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","onPick","ready","selected","restored","word","include","picked","setPicked","shown","setShown","ownedHere","setOwnedHere","purchase","value","undefined","pickedRow","rows","find","ownedOverride","has","refused","error","status","verdict","settled","length","readyRef","current","reported","onPickRef","handedBack","options","buy","outcome","add","aria-busy","aria-label","sx","display","gap","gridTemplateColumns","xs","sm","md","Array","from","_","index","aspectRatio","borderRadius","data-starter-shelf","loading","severity","action","size","onClick","refresh","message","component","href","target","rel","columns","onChange","candidate","data-starter-owned","data-starter-buy","disabled","busy"],"mappings":"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"}
|
|
@@ -74,7 +74,8 @@ import { RATING_FIELD } from "./model/rating-field.js";
|
|
|
74
74
|
registerPluginSiteStarterSource({
|
|
75
75
|
search: async (input, viewer)=>(await starters()).search(input, viewer),
|
|
76
76
|
resolve: async (choice, viewer)=>(await starters()).resolve(choice, viewer),
|
|
77
|
-
installed: async (choice, viewer, site)=>(await starters()).installed(choice, viewer, site)
|
|
77
|
+
installed: async (choice, viewer, site)=>(await starters()).installed(choice, viewer, site),
|
|
78
|
+
describe: async (choice, viewer)=>(await starters()).describe(choice, viewer)
|
|
78
79
|
}, {
|
|
79
80
|
pluginId: BUNDLE_ID
|
|
80
81
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/declarations.server.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\n// The registry from its own module, not the plugin-manager barrel: boot needs\n// the registry and nothing else.\nimport { registerCustomFieldType } from '@aglyn/aglyn/plugin-manager/custom-fields'\nimport {\n listPluginOrgErasers,\n registerPluginOrgEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-org-erasure'\nimport { registerPluginRevocationReader } from '@aglyn/aglyn/plugin-manager/plugin-revocations'\nimport { registerPluginSiteStarterSource } from '@aglyn/aglyn/plugin-manager/plugin-site-starters'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { RATING_FIELD } from './model/rating-field'\n\n/**\n * The marketplace plugin's server declarations: the light registrations core\n * reads at boot, before any surface loads.\n *\n * The `rating` field type's validator (AGL-434), the marketplace's share of\n * a workspace erasure, its kill switch as another plugin reads it, and the\n * site starters \"Create site\" offers (AGL-4049).\n *\n * The validator: A dataset field of this type\n * can be written by a path that never loads the marketplace — a visitor's\n * form submission and an automation step, both in the tenant (AGL-2773) — so\n * the validator registers from here, which every app runs at boot, rather\n * than only from the console API surface. Pure data: no React, no Admin SDK.\n */\nexport function registerMarketplaceServerDeclarations(): void {\n registerCustomFieldType(RATING_FIELD)\n /*\n * The organization's public marketplace identity, erased with it (AGL-1970).\n * Declared REQUIRED in `plugins.config.json`: the profile carries a payout\n * identifier on a world-readable document, so an erasure refuses to run\n * without this eraser rather than report a workspace erased with it\n * standing. From here, which every app and the erasure script run at boot;\n * the Admin SDK arrives with the first erasure, not with the boot.\n */\n if (!listPluginOrgErasers().includes(BUNDLE_ID)) {\n registerPluginOrgEraser(\n async (request) => {\n const { createPublisherIdentityEraser } = await import('./server/publisher-erasure')\n return createPublisherIdentityEraser()(request)\n },\n { pluginId: BUNDLE_ID },\n )\n }\n /*\n * The kill switch (`plugin-revocations`, AGL-3080): the send path asks it\n * before mailing a design installed from a listing, in whichever process\n * sends. The Admin SDK arrives with the first read.\n */\n registerPluginRevocationReader(\n {\n async revocation(listingId) {\n const { marketplaceRevocationReader } = await import('./server/revocation-reader')\n return marketplaceRevocationReader.revocation(listingId)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n /*\n * Site starters (AGL-4049): \"Create site\" searches the marketplace's\n * `siteStarter` listings and creates a site from the one picked, through\n * core's `core.site-starters` seam. Registering reads nothing; the Admin SDK\n * arrives with the first search, not with the boot. The same plugin\n * registering again replaces itself, so a re-run of these declarations is\n * safe.\n */\n const starters = () => import('./server/site-starter-source').then((m) => m.marketplaceSiteStarterSource)\n registerPluginSiteStarterSource(\n {\n search: async (input, viewer) => (await starters()).search(input, viewer),\n resolve: async (choice, viewer) => (await starters()).resolve(choice, viewer),\n installed: async (choice, viewer, site) => (await starters()).installed(choice, viewer, site),\n },\n { pluginId: BUNDLE_ID },\n )\n}\n"],"names":["registerCustomFieldType","listPluginOrgErasers","registerPluginOrgEraser","registerPluginRevocationReader","registerPluginSiteStarterSource","BUNDLE_ID","RATING_FIELD","registerMarketplaceServerDeclarations","includes","request","createPublisherIdentityEraser","pluginId","revocation","listingId","marketplaceRevocationReader","starters","then","m","marketplaceSiteStarterSource","search","input","viewer","resolve","choice","installed","site"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E;AAC9E,iCAAiC;AACjC,SAASA,uBAAuB,QAAQ,4CAA2C;AACnF,SACEC,oBAAoB,EACpBC,uBAAuB,QAClB,iDAAgD;AACvD,SAASC,8BAA8B,QAAQ,iDAAgD;AAC/F,SAASC,+BAA+B,QAAQ,mDAAkD;AAClG,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,YAAY,QAAQ,0BAAsB;AAEnD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IACdP,wBAAwBM;IACxB;;;;;;;GAOC,GACD,IAAI,CAACL,uBAAuBO,QAAQ,CAACH,YAAY;QAC/CH,wBACE,OAAOO;YACL,MAAM,EAAEC,6BAA6B,EAAE,GAAG,MAAM,MAAM,CAAC;YACvD,OAAOA,gCAAgCD;QACzC,GACA;YAAEE,UAAUN;QAAU;IAE1B;IACA;;;;GAIC,GACDF,+BACE;QACE,MAAMS,YAAWC,SAAS;YACxB,MAAM,EAAEC,2BAA2B,EAAE,GAAG,MAAM,MAAM,CAAC;YACrD,OAAOA,4BAA4BF,UAAU,CAACC;QAChD;IACF,GACA;QAAEF,UAAUN;IAAU;IAExB;;;;;;;GAOC,GACD,MAAMU,WAAW,IAAM,MAAM,CAAC,mCAAgCC,IAAI,CAAC,CAACC,IAAMA,EAAEC,4BAA4B;IACxGd,gCACE;QACEe,QAAQ,OAAOC,OAAOC,SAAW,AAAC,CAAA,MAAMN,UAAS,EAAGI,MAAM,CAACC,OAAOC;QAClEC,SAAS,OAAOC,QAAQF,SAAW,AAAC,CAAA,MAAMN,UAAS,EAAGO,OAAO,CAACC,QAAQF;QACtEG,WAAW,OAAOD,QAAQF,QAAQI,OAAS,AAAC,CAAA,MAAMV,UAAS,EAAGS,SAAS,CAACD,QAAQF,QAAQI;
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/declarations.server.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\n// The registry from its own module, not the plugin-manager barrel: boot needs\n// the registry and nothing else.\nimport { registerCustomFieldType } from '@aglyn/aglyn/plugin-manager/custom-fields'\nimport {\n listPluginOrgErasers,\n registerPluginOrgEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-org-erasure'\nimport { registerPluginRevocationReader } from '@aglyn/aglyn/plugin-manager/plugin-revocations'\nimport { registerPluginSiteStarterSource } from '@aglyn/aglyn/plugin-manager/plugin-site-starters'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { RATING_FIELD } from './model/rating-field'\n\n/**\n * The marketplace plugin's server declarations: the light registrations core\n * reads at boot, before any surface loads.\n *\n * The `rating` field type's validator (AGL-434), the marketplace's share of\n * a workspace erasure, its kill switch as another plugin reads it, and the\n * site starters \"Create site\" offers (AGL-4049).\n *\n * The validator: A dataset field of this type\n * can be written by a path that never loads the marketplace — a visitor's\n * form submission and an automation step, both in the tenant (AGL-2773) — so\n * the validator registers from here, which every app runs at boot, rather\n * than only from the console API surface. Pure data: no React, no Admin SDK.\n */\nexport function registerMarketplaceServerDeclarations(): void {\n registerCustomFieldType(RATING_FIELD)\n /*\n * The organization's public marketplace identity, erased with it (AGL-1970).\n * Declared REQUIRED in `plugins.config.json`: the profile carries a payout\n * identifier on a world-readable document, so an erasure refuses to run\n * without this eraser rather than report a workspace erased with it\n * standing. From here, which every app and the erasure script run at boot;\n * the Admin SDK arrives with the first erasure, not with the boot.\n */\n if (!listPluginOrgErasers().includes(BUNDLE_ID)) {\n registerPluginOrgEraser(\n async (request) => {\n const { createPublisherIdentityEraser } = await import('./server/publisher-erasure')\n return createPublisherIdentityEraser()(request)\n },\n { pluginId: BUNDLE_ID },\n )\n }\n /*\n * The kill switch (`plugin-revocations`, AGL-3080): the send path asks it\n * before mailing a design installed from a listing, in whichever process\n * sends. The Admin SDK arrives with the first read.\n */\n registerPluginRevocationReader(\n {\n async revocation(listingId) {\n const { marketplaceRevocationReader } = await import('./server/revocation-reader')\n return marketplaceRevocationReader.revocation(listingId)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n /*\n * Site starters (AGL-4049): \"Create site\" searches the marketplace's\n * `siteStarter` listings and creates a site from the one picked, through\n * core's `core.site-starters` seam. Registering reads nothing; the Admin SDK\n * arrives with the first search, not with the boot. The same plugin\n * registering again replaces itself, so a re-run of these declarations is\n * safe.\n */\n const starters = () => import('./server/site-starter-source').then((m) => m.marketplaceSiteStarterSource)\n registerPluginSiteStarterSource(\n {\n search: async (input, viewer) => (await starters()).search(input, viewer),\n resolve: async (choice, viewer) => (await starters()).resolve(choice, viewer),\n installed: async (choice, viewer, site) => (await starters()).installed(choice, viewer, site),\n describe: async (choice, viewer) => (await starters()).describe(choice, viewer),\n },\n { pluginId: BUNDLE_ID },\n )\n}\n"],"names":["registerCustomFieldType","listPluginOrgErasers","registerPluginOrgEraser","registerPluginRevocationReader","registerPluginSiteStarterSource","BUNDLE_ID","RATING_FIELD","registerMarketplaceServerDeclarations","includes","request","createPublisherIdentityEraser","pluginId","revocation","listingId","marketplaceRevocationReader","starters","then","m","marketplaceSiteStarterSource","search","input","viewer","resolve","choice","installed","site","describe"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E;AAC9E,iCAAiC;AACjC,SAASA,uBAAuB,QAAQ,4CAA2C;AACnF,SACEC,oBAAoB,EACpBC,uBAAuB,QAClB,iDAAgD;AACvD,SAASC,8BAA8B,QAAQ,iDAAgD;AAC/F,SAASC,+BAA+B,QAAQ,mDAAkD;AAClG,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,YAAY,QAAQ,0BAAsB;AAEnD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IACdP,wBAAwBM;IACxB;;;;;;;GAOC,GACD,IAAI,CAACL,uBAAuBO,QAAQ,CAACH,YAAY;QAC/CH,wBACE,OAAOO;YACL,MAAM,EAAEC,6BAA6B,EAAE,GAAG,MAAM,MAAM,CAAC;YACvD,OAAOA,gCAAgCD;QACzC,GACA;YAAEE,UAAUN;QAAU;IAE1B;IACA;;;;GAIC,GACDF,+BACE;QACE,MAAMS,YAAWC,SAAS;YACxB,MAAM,EAAEC,2BAA2B,EAAE,GAAG,MAAM,MAAM,CAAC;YACrD,OAAOA,4BAA4BF,UAAU,CAACC;QAChD;IACF,GACA;QAAEF,UAAUN;IAAU;IAExB;;;;;;;GAOC,GACD,MAAMU,WAAW,IAAM,MAAM,CAAC,mCAAgCC,IAAI,CAAC,CAACC,IAAMA,EAAEC,4BAA4B;IACxGd,gCACE;QACEe,QAAQ,OAAOC,OAAOC,SAAW,AAAC,CAAA,MAAMN,UAAS,EAAGI,MAAM,CAACC,OAAOC;QAClEC,SAAS,OAAOC,QAAQF,SAAW,AAAC,CAAA,MAAMN,UAAS,EAAGO,OAAO,CAACC,QAAQF;QACtEG,WAAW,OAAOD,QAAQF,QAAQI,OAAS,AAAC,CAAA,MAAMV,UAAS,EAAGS,SAAS,CAACD,QAAQF,QAAQI;QACxFC,UAAU,OAAOH,QAAQF,SAAW,AAAC,CAAA,MAAMN,UAAS,EAAGW,QAAQ,CAACH,QAAQF;IAC1E,GACA;QAAEV,UAAUN;IAAU;AAE1B"}
|