@aglyn/plugins-marketplace 1.0.0-beta.146 → 1.0.0-beta.149
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 +11 -11
- package/src/lib/components/publish-artifact-dialog.component.d.ts +21 -0
- package/src/lib/components/publish-artifact-dialog.component.js +327 -0
- package/src/lib/components/publish-artifact-dialog.component.js.map +1 -0
- package/src/lib/plugin.js +11 -0
- package/src/lib/plugin.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/plugins-marketplace",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.149",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,16 +25,16 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-ui-jsx": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-ui-next": "1.0.0-beta.
|
|
32
|
-
"@aglyn/shared-ui-snackstack": "1.0.0-beta.
|
|
33
|
-
"@aglyn/shared-util-email": "1.0.0-beta.
|
|
34
|
-
"@aglyn/shared-util-http": "1.0.0-beta.
|
|
35
|
-
"@aglyn/tenant-data-admin": "1.0.0-beta.
|
|
36
|
-
"@aglyn/tenant-feature-instance": "1.0.0-beta.
|
|
37
|
-
"@aglyn/tenant-runtime": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.149",
|
|
29
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.149",
|
|
30
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.149",
|
|
31
|
+
"@aglyn/shared-ui-next": "1.0.0-beta.149",
|
|
32
|
+
"@aglyn/shared-ui-snackstack": "1.0.0-beta.149",
|
|
33
|
+
"@aglyn/shared-util-email": "1.0.0-beta.149",
|
|
34
|
+
"@aglyn/shared-util-http": "1.0.0-beta.149",
|
|
35
|
+
"@aglyn/tenant-data-admin": "1.0.0-beta.149",
|
|
36
|
+
"@aglyn/tenant-feature-instance": "1.0.0-beta.149",
|
|
37
|
+
"@aglyn/tenant-runtime": "1.0.0-beta.149",
|
|
38
38
|
"@swc/helpers": "0.5.23"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ConsoleArtifactPublishZoneProps } from '@aglyn/aglyn';
|
|
2
|
+
/**
|
|
3
|
+
* Publish an artifact to the marketplace (AGL-672, moved out of the console
|
|
4
|
+
* app by AGL-3080).
|
|
5
|
+
*
|
|
6
|
+
* The publish form is identical across artifact types — name, description,
|
|
7
|
+
* category, price — and only the endpoint and identifying fields differ, so
|
|
8
|
+
* this takes both rather than being copied per type. Every gate that
|
|
9
|
+
* matters (plan, publisher profile, payouts, host role) lives on the server;
|
|
10
|
+
* this surfaces the server's message rather than trying to predict it.
|
|
11
|
+
*
|
|
12
|
+
* Drawn through the `hostArtifactPublish` zone, so the page that offers the
|
|
13
|
+
* publish keeps the control that opens it and never imports this. A page
|
|
14
|
+
* with no widget on that zone leaves the offer out entirely, which is why
|
|
15
|
+
* this may safely draw nothing for a kind it does not sell.
|
|
16
|
+
*/
|
|
17
|
+
export declare function PublishArtifactDialog({ artifact, onClose, }: ConsoleArtifactPublishZoneProps): import("react").JSX.Element;
|
|
18
|
+
export declare namespace PublishArtifactDialog {
|
|
19
|
+
var displayName: string;
|
|
20
|
+
}
|
|
21
|
+
export default PublishArtifactDialog;
|
|
@@ -0,0 +1,327 @@
|
|
|
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 { isBelowMarketplacePriceFloor, marketplacePriceCostNote, marketplacePriceFloorHint } from "@aglyn/aglyn";
|
|
20
|
+
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
21
|
+
import { useUser } from "@aglyn/tenant-feature-instance";
|
|
22
|
+
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
23
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack, TextField, Typography } from "@mui/material";
|
|
24
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
25
|
+
/**
|
|
26
|
+
* WHERE EACH KIND GOES, which is the knowledge that used to sit in the app
|
|
27
|
+
* (AGL-3080).
|
|
28
|
+
*
|
|
29
|
+
* A console page hands over what it has — a kind, the scope holding it, the
|
|
30
|
+
* document — and this is the only place that turns it into a request. The
|
|
31
|
+
* pages that offer publishing named the endpoint, the payload key and the
|
|
32
|
+
* noun themselves, which made them files that could not compile without a
|
|
33
|
+
* marketplace and could not be right without being kept in step with one.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ A KIND THIS DOES NOT KNOW IS SAID OUT LOUD, not drawn as nothing. It
|
|
36
|
+
* means a console offering to publish something this marketplace does not
|
|
37
|
+
* sell — the two lists have gone out of step — and the person has already
|
|
38
|
+
* clicked. Drawing nothing would make the control look broken with no way to
|
|
39
|
+
* tell what happened, and guessing an endpoint from the kind would post to a
|
|
40
|
+
* route that does not exist and report the 404 to the publisher.
|
|
41
|
+
*
|
|
42
|
+
* The control itself is a separate matter: a page only offers the publish
|
|
43
|
+
* when this zone has a widget at all, so a workspace with no marketplace
|
|
44
|
+
* never gets here.
|
|
45
|
+
*/ function publishRequestFor(artifact) {
|
|
46
|
+
var _artifact_hostId, _artifact_orgId, _artifact_artifactId;
|
|
47
|
+
const hostId = (_artifact_hostId = artifact.hostId) != null ? _artifact_hostId : '';
|
|
48
|
+
const orgId = (_artifact_orgId = artifact.orgId) != null ? _artifact_orgId : '';
|
|
49
|
+
const artifactId = (_artifact_artifactId = artifact.artifactId) != null ? _artifact_artifactId : '';
|
|
50
|
+
switch(artifact.kind){
|
|
51
|
+
case 'layout':
|
|
52
|
+
return {
|
|
53
|
+
endpoint: 'marketplace/publish-layout',
|
|
54
|
+
payload: {
|
|
55
|
+
hostId,
|
|
56
|
+
layoutId: artifactId
|
|
57
|
+
},
|
|
58
|
+
noun: 'layout',
|
|
59
|
+
categoryPlaceholder: 'e.g. Marketing, Docs, Storefront'
|
|
60
|
+
};
|
|
61
|
+
case 'component':
|
|
62
|
+
return {
|
|
63
|
+
endpoint: 'marketplace/publish',
|
|
64
|
+
payload: {
|
|
65
|
+
hostId,
|
|
66
|
+
componentId: artifactId
|
|
67
|
+
},
|
|
68
|
+
noun: 'component'
|
|
69
|
+
};
|
|
70
|
+
case 'site':
|
|
71
|
+
return {
|
|
72
|
+
endpoint: 'marketplace/publish-template',
|
|
73
|
+
payload: {
|
|
74
|
+
hostId
|
|
75
|
+
},
|
|
76
|
+
noun: 'site template'
|
|
77
|
+
};
|
|
78
|
+
case 'theme':
|
|
79
|
+
return {
|
|
80
|
+
endpoint: 'marketplace/publish-theme',
|
|
81
|
+
payload: {
|
|
82
|
+
hostId
|
|
83
|
+
},
|
|
84
|
+
noun: 'theme'
|
|
85
|
+
};
|
|
86
|
+
// Datasets are org-scoped, so this route takes orgId rather than hostId.
|
|
87
|
+
case 'datasetSchema':
|
|
88
|
+
return {
|
|
89
|
+
endpoint: 'marketplace/publish-dataset-schema',
|
|
90
|
+
payload: {
|
|
91
|
+
orgId,
|
|
92
|
+
datasetId: artifactId
|
|
93
|
+
},
|
|
94
|
+
noun: 'dataset schema'
|
|
95
|
+
};
|
|
96
|
+
case 'emailTemplate':
|
|
97
|
+
return {
|
|
98
|
+
endpoint: 'marketplace/publish-email-template',
|
|
99
|
+
payload: {
|
|
100
|
+
hostId,
|
|
101
|
+
templateKey: artifactId
|
|
102
|
+
},
|
|
103
|
+
noun: 'email template'
|
|
104
|
+
};
|
|
105
|
+
case 'emailStarter':
|
|
106
|
+
return {
|
|
107
|
+
endpoint: 'marketplace/publish-email-starter',
|
|
108
|
+
payload: {
|
|
109
|
+
hostId,
|
|
110
|
+
screenId: artifactId
|
|
111
|
+
},
|
|
112
|
+
noun: 'email starter'
|
|
113
|
+
};
|
|
114
|
+
default:
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Publish an artifact to the marketplace (AGL-672, moved out of the console
|
|
120
|
+
* app by AGL-3080).
|
|
121
|
+
*
|
|
122
|
+
* The publish form is identical across artifact types — name, description,
|
|
123
|
+
* category, price — and only the endpoint and identifying fields differ, so
|
|
124
|
+
* this takes both rather than being copied per type. Every gate that
|
|
125
|
+
* matters (plan, publisher profile, payouts, host role) lives on the server;
|
|
126
|
+
* this surfaces the server's message rather than trying to predict it.
|
|
127
|
+
*
|
|
128
|
+
* Drawn through the `hostArtifactPublish` zone, so the page that offers the
|
|
129
|
+
* publish keeps the control that opens it and never imports this. A page
|
|
130
|
+
* with no widget on that zone leaves the offer out entirely, which is why
|
|
131
|
+
* this may safely draw nothing for a kind it does not sell.
|
|
132
|
+
*/ export function PublishArtifactDialog({ artifact, onClose }) {
|
|
133
|
+
var _ref, _ref1, _ref2, _marketplacePriceCostNote;
|
|
134
|
+
// Memoized because it is a dependency of the publish callback: rebuilt
|
|
135
|
+
// every render, it would rebuild that callback every render too.
|
|
136
|
+
const target = useMemo(()=>artifact ? publishRequestFor(artifact) : null, [
|
|
137
|
+
artifact
|
|
138
|
+
]);
|
|
139
|
+
const { data: user } = useUser();
|
|
140
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
141
|
+
const [name, setName] = useState('');
|
|
142
|
+
const [description, setDescription] = useState('');
|
|
143
|
+
const [category, setCategory] = useState('');
|
|
144
|
+
const [price, setPrice] = useState('');
|
|
145
|
+
const [busy, setBusy] = useState(false);
|
|
146
|
+
useEffect(()=>{
|
|
147
|
+
var _artifact_displayName, _artifact_description;
|
|
148
|
+
if (!artifact) return;
|
|
149
|
+
setName((_artifact_displayName = artifact.displayName) != null ? _artifact_displayName : '');
|
|
150
|
+
setDescription((_artifact_description = artifact.description) != null ? _artifact_description : '');
|
|
151
|
+
setCategory('');
|
|
152
|
+
setPrice('');
|
|
153
|
+
}, [
|
|
154
|
+
artifact
|
|
155
|
+
]);
|
|
156
|
+
const handlePublish = useCallback(async ()=>{
|
|
157
|
+
if (!target || !name.trim() || busy) return;
|
|
158
|
+
setBusy(true);
|
|
159
|
+
try {
|
|
160
|
+
const response = await authorizedFetch(user, `/api/${target.endpoint}`, {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
headers: {
|
|
163
|
+
'Content-Type': 'application/json'
|
|
164
|
+
},
|
|
165
|
+
body: JSON.stringify(_extends({}, target.payload, {
|
|
166
|
+
displayName: name.trim(),
|
|
167
|
+
description: description.trim(),
|
|
168
|
+
category: category.trim(),
|
|
169
|
+
priceUsd: Number(price) || 0
|
|
170
|
+
}))
|
|
171
|
+
});
|
|
172
|
+
const payload = await response.json().catch(()=>({}));
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
var _ref;
|
|
175
|
+
// 412 means a setup step is missing (publisher profile, payouts) —
|
|
176
|
+
// actionable, so it reads as a warning rather than an error.
|
|
177
|
+
return void enqueueSnackbar((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Publish failed', {
|
|
178
|
+
variant: response.status === 412 ? 'warning' : 'error',
|
|
179
|
+
allowDuplicate: true
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
enqueueSnackbar(`Published v${payload.version} to the marketplace`, {
|
|
183
|
+
variant: 'success',
|
|
184
|
+
persist: false
|
|
185
|
+
});
|
|
186
|
+
onClose();
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error(error);
|
|
189
|
+
enqueueSnackbar('An error has occurred', {
|
|
190
|
+
variant: 'error',
|
|
191
|
+
allowDuplicate: true
|
|
192
|
+
});
|
|
193
|
+
} finally{
|
|
194
|
+
setBusy(false);
|
|
195
|
+
}
|
|
196
|
+
}, [
|
|
197
|
+
target,
|
|
198
|
+
name,
|
|
199
|
+
description,
|
|
200
|
+
category,
|
|
201
|
+
price,
|
|
202
|
+
busy,
|
|
203
|
+
user,
|
|
204
|
+
enqueueSnackbar,
|
|
205
|
+
onClose
|
|
206
|
+
]);
|
|
207
|
+
if (artifact && !target) {
|
|
208
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
209
|
+
open: true,
|
|
210
|
+
onClose: onClose,
|
|
211
|
+
maxWidth: "xs",
|
|
212
|
+
fullWidth: true,
|
|
213
|
+
children: [
|
|
214
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
215
|
+
children: 'Nothing publishes this'
|
|
216
|
+
}),
|
|
217
|
+
/*#__PURE__*/ _jsx(DialogContent, {
|
|
218
|
+
children: /*#__PURE__*/ _jsx(Typography, {
|
|
219
|
+
variant: "body2",
|
|
220
|
+
color: "text.secondary",
|
|
221
|
+
children: `This marketplace does not publish a ${artifact.kind}, so there ` + 'is nowhere to send it. Nothing was changed.'
|
|
222
|
+
})
|
|
223
|
+
}),
|
|
224
|
+
/*#__PURE__*/ _jsx(DialogActions, {
|
|
225
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
226
|
+
size: "small",
|
|
227
|
+
onClick: onClose,
|
|
228
|
+
children: 'Close'
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
235
|
+
open: !!target,
|
|
236
|
+
onClose: busy ? undefined : onClose,
|
|
237
|
+
maxWidth: "xs",
|
|
238
|
+
fullWidth: true,
|
|
239
|
+
children: [
|
|
240
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
241
|
+
children: `Publish ${(_ref = target == null ? void 0 : target.noun) != null ? _ref : 'artifact'}`
|
|
242
|
+
}),
|
|
243
|
+
/*#__PURE__*/ _jsx(DialogContent, {
|
|
244
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
245
|
+
spacing: 2,
|
|
246
|
+
sx: {
|
|
247
|
+
pt: 1
|
|
248
|
+
},
|
|
249
|
+
children: [
|
|
250
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
251
|
+
variant: "body2",
|
|
252
|
+
color: "text.secondary",
|
|
253
|
+
children: `Publishes the current published version of this ` + `${(_ref1 = target == null ? void 0 : target.noun) != null ? _ref1 : 'artifact'} so other organizations can ` + 'install it. Your site is unaffected.'
|
|
254
|
+
}),
|
|
255
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
256
|
+
autoFocus: true,
|
|
257
|
+
size: "small",
|
|
258
|
+
label: "Listing name",
|
|
259
|
+
value: name,
|
|
260
|
+
onChange: (event)=>setName(event.target.value),
|
|
261
|
+
disabled: busy,
|
|
262
|
+
fullWidth: true
|
|
263
|
+
}),
|
|
264
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
265
|
+
size: "small",
|
|
266
|
+
label: "Description",
|
|
267
|
+
value: description,
|
|
268
|
+
onChange: (event)=>setDescription(event.target.value),
|
|
269
|
+
disabled: busy,
|
|
270
|
+
multiline: true,
|
|
271
|
+
minRows: 2,
|
|
272
|
+
fullWidth: true
|
|
273
|
+
}),
|
|
274
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
275
|
+
size: "small",
|
|
276
|
+
label: "Category",
|
|
277
|
+
placeholder: (_ref2 = target == null ? void 0 : target.categoryPlaceholder) != null ? _ref2 : 'e.g. Marketing, Docs',
|
|
278
|
+
value: category,
|
|
279
|
+
onChange: (event)=>setCategory(event.target.value),
|
|
280
|
+
disabled: busy,
|
|
281
|
+
fullWidth: true
|
|
282
|
+
}),
|
|
283
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
284
|
+
size: "small",
|
|
285
|
+
label: "Price (USD)",
|
|
286
|
+
placeholder: "0 = free",
|
|
287
|
+
// The minimum price (AGL-2343). Marketplace checkout is a
|
|
288
|
+
// destination charge, so Stripe's fee comes out of the PLATFORM's
|
|
289
|
+
// balance while the seller is transferred a fixed share — at $1 the
|
|
290
|
+
// fee is larger than the whole platform cut. The publish route
|
|
291
|
+
// refuses anything under the floor, so the field says so before the
|
|
292
|
+
// publisher gets there and the button holds.
|
|
293
|
+
error: isBelowMarketplacePriceFloor(price),
|
|
294
|
+
helperText: (_marketplacePriceCostNote = marketplacePriceCostNote(price)) != null ? _marketplacePriceCostNote : marketplacePriceFloorHint('Paid listings need payouts set up on your marketplace profile.'),
|
|
295
|
+
value: price,
|
|
296
|
+
onChange: (event)=>setPrice(event.target.value.replace(/[^0-9]/g, '')),
|
|
297
|
+
disabled: busy,
|
|
298
|
+
fullWidth: true
|
|
299
|
+
})
|
|
300
|
+
]
|
|
301
|
+
})
|
|
302
|
+
}),
|
|
303
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
304
|
+
children: [
|
|
305
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
306
|
+
size: "small",
|
|
307
|
+
onClick: onClose,
|
|
308
|
+
disabled: busy,
|
|
309
|
+
children: 'Cancel'
|
|
310
|
+
}),
|
|
311
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
312
|
+
size: "small",
|
|
313
|
+
variant: "contained",
|
|
314
|
+
color: "primary",
|
|
315
|
+
disabled: busy || !name.trim() || isBelowMarketplacePriceFloor(price),
|
|
316
|
+
onClick: ()=>void handlePublish(),
|
|
317
|
+
children: busy ? 'Publishing…' : 'Publish'
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
})
|
|
321
|
+
]
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
PublishArtifactDialog.displayName = 'PublishArtifactDialog';
|
|
325
|
+
export default PublishArtifactDialog;
|
|
326
|
+
|
|
327
|
+
//# sourceMappingURL=publish-artifact-dialog.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publish-artifact-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'use client'\n\nimport {\n isBelowMarketplacePriceFloor,\n marketplacePriceCostNote,\n marketplacePriceFloorHint,\n} from '@aglyn/aglyn'\nimport type {\n ConsoleArtifactPublishZoneProps,\n ConsolePublishableArtifact,\n} from '@aglyn/aglyn'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\n\n/** One kind's publish route, and the words a person reads about it. */\ninterface PublishRequest {\n /** Plugin API path, e.g. `marketplace/publish-layout`. */\n endpoint: string\n /** Extra body fields identifying what is being published. */\n payload: Record<string, unknown>\n /** Noun used in copy: \"layout\", \"component\", … */\n noun: string\n categoryPlaceholder?: string\n}\n\n/**\n * WHERE EACH KIND GOES, which is the knowledge that used to sit in the app\n * (AGL-3080).\n *\n * A console page hands over what it has — a kind, the scope holding it, the\n * document — and this is the only place that turns it into a request. The\n * pages that offer publishing named the endpoint, the payload key and the\n * noun themselves, which made them files that could not compile without a\n * marketplace and could not be right without being kept in step with one.\n *\n * ⚠️ A KIND THIS DOES NOT KNOW IS SAID OUT LOUD, not drawn as nothing. It\n * means a console offering to publish something this marketplace does not\n * sell — the two lists have gone out of step — and the person has already\n * clicked. Drawing nothing would make the control look broken with no way to\n * tell what happened, and guessing an endpoint from the kind would post to a\n * route that does not exist and report the 404 to the publisher.\n *\n * The control itself is a separate matter: a page only offers the publish\n * when this zone has a widget at all, so a workspace with no marketplace\n * never gets here.\n */\nfunction publishRequestFor(\n artifact: ConsolePublishableArtifact,\n): PublishRequest | null {\n const hostId = artifact.hostId ?? ''\n const orgId = artifact.orgId ?? ''\n const artifactId = artifact.artifactId ?? ''\n switch (artifact.kind) {\n case 'layout':\n return {\n endpoint: 'marketplace/publish-layout',\n payload: { hostId, layoutId: artifactId },\n noun: 'layout',\n categoryPlaceholder: 'e.g. Marketing, Docs, Storefront',\n }\n case 'component':\n return {\n endpoint: 'marketplace/publish',\n payload: { hostId, componentId: artifactId },\n noun: 'component',\n }\n case 'site':\n return {\n endpoint: 'marketplace/publish-template',\n payload: { hostId },\n noun: 'site template',\n }\n case 'theme':\n return {\n endpoint: 'marketplace/publish-theme',\n payload: { hostId },\n noun: 'theme',\n }\n // Datasets are org-scoped, so this route takes orgId rather than hostId.\n case 'datasetSchema':\n return {\n endpoint: 'marketplace/publish-dataset-schema',\n payload: { orgId, datasetId: artifactId },\n noun: 'dataset schema',\n }\n case 'emailTemplate':\n return {\n endpoint: 'marketplace/publish-email-template',\n payload: { hostId, templateKey: artifactId },\n noun: 'email template',\n }\n case 'emailStarter':\n return {\n endpoint: 'marketplace/publish-email-starter',\n payload: { hostId, screenId: artifactId },\n noun: 'email starter',\n }\n default:\n return null\n }\n}\n\n/**\n * Publish an artifact to the marketplace (AGL-672, moved out of the console\n * app by AGL-3080).\n *\n * The publish form is identical across artifact types — name, description,\n * category, price — and only the endpoint and identifying fields differ, so\n * this takes both rather than being copied per type. Every gate that\n * matters (plan, publisher profile, payouts, host role) lives on the server;\n * this surfaces the server's message rather than trying to predict it.\n *\n * Drawn through the `hostArtifactPublish` zone, so the page that offers the\n * publish keeps the control that opens it and never imports this. A page\n * with no widget on that zone leaves the offer out entirely, which is why\n * this may safely draw nothing for a kind it does not sell.\n */\nexport function PublishArtifactDialog({\n artifact,\n onClose,\n}: ConsoleArtifactPublishZoneProps) {\n // Memoized because it is a dependency of the publish callback: rebuilt\n // every render, it would rebuild that callback every render too.\n const target = useMemo(\n () => (artifact ? publishRequestFor(artifact) : null),\n [artifact],\n )\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [category, setCategory] = useState('')\n const [price, setPrice] = useState('')\n const [busy, setBusy] = useState(false)\n\n useEffect(() => {\n if (!artifact) return\n setName(artifact.displayName ?? '')\n setDescription(artifact.description ?? '')\n setCategory('')\n setPrice('')\n }, [artifact])\n\n const handlePublish = useCallback(async () => {\n if (!target || !name.trim() || busy) return\n setBusy(true)\n try {\n const response = await authorizedFetch(user, `/api/${target.endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...target.payload,\n displayName: name.trim(),\n description: description.trim(),\n category: category.trim(),\n priceUsd: Number(price) || 0,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n // 412 means a setup step is missing (publisher profile, payouts) —\n // actionable, so it reads as a warning rather than an error.\n return void enqueueSnackbar(payload?.error ?? 'Publish failed', {\n variant: response.status === 412 ? 'warning' : 'error',\n allowDuplicate: true,\n })\n }\n enqueueSnackbar(`Published v${payload.version} to the marketplace`, {\n variant: 'success',\n persist: false,\n })\n onClose()\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n target,\n name,\n description,\n category,\n price,\n busy,\n user,\n enqueueSnackbar,\n onClose,\n ])\n\n if (artifact && !target) {\n return (\n <Dialog open onClose={onClose} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Nothing publishes this'}</DialogTitle>\n <DialogContent>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This marketplace does not publish a ${artifact.kind}, so there ` +\n 'is nowhere to send it. Nothing was changed.'}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose}>\n {'Close'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n }\n\n return (\n <Dialog\n open={!!target}\n onClose={busy ? undefined : onClose}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{`Publish ${target?.noun ?? 'artifact'}`}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Publishes the current published version of this ` +\n `${target?.noun ?? 'artifact'} so other organizations can ` +\n 'install it. Your site is unaffected.'}\n </Typography>\n <TextField\n autoFocus\n size=\"small\"\n label=\"Listing name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Description\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n disabled={busy}\n multiline\n minRows={2}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Category\"\n placeholder={target?.categoryPlaceholder ?? 'e.g. Marketing, Docs'}\n value={category}\n onChange={(event) => setCategory(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Price (USD)\"\n placeholder=\"0 = free\"\n // The minimum price (AGL-2343). Marketplace checkout is a\n // destination charge, so Stripe's fee comes out of the PLATFORM's\n // balance while the seller is transferred a fixed share — at $1 the\n // fee is larger than the whole platform cut. The publish route\n // refuses anything under the floor, so the field says so before the\n // publisher gets there and the button holds.\n error={isBelowMarketplacePriceFloor(price)}\n helperText={\n marketplacePriceCostNote(price) ??\n marketplacePriceFloorHint(\n 'Paid listings need payouts set up on your marketplace profile.',\n )\n }\n value={price}\n onChange={(event) =>\n setPrice(event.target.value.replace(/[^0-9]/g, ''))\n }\n disabled={busy}\n fullWidth\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=\"primary\"\n disabled={busy || !name.trim() || isBelowMarketplacePriceFloor(price)}\n onClick={() => void handlePublish()}\n >\n {busy ? 'Publishing…' : 'Publish'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nPublishArtifactDialog.displayName = 'PublishArtifactDialog'\n\nexport default PublishArtifactDialog\n"],"names":["isBelowMarketplacePriceFloor","marketplacePriceCostNote","marketplacePriceFloorHint","useSnackbar","useUser","authorizedFetch","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","TextField","Typography","useCallback","useEffect","useMemo","useState","publishRequestFor","artifact","hostId","orgId","artifactId","kind","endpoint","payload","layoutId","noun","categoryPlaceholder","componentId","datasetId","templateKey","screenId","PublishArtifactDialog","onClose","target","data","user","enqueueSnackbar","name","setName","description","setDescription","category","setCategory","price","setPrice","busy","setBusy","displayName","handlePublish","trim","response","method","headers","body","JSON","stringify","priceUsd","Number","json","catch","ok","error","variant","status","allowDuplicate","version","persist","console","open","maxWidth","fullWidth","color","size","onClick","undefined","spacing","sx","pt","autoFocus","label","value","onChange","event","disabled","multiline","minRows","placeholder","helperText","replace"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SACEA,4BAA4B,EAC5BC,wBAAwB,EACxBC,yBAAyB,QACpB,eAAc;AAKrB,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SACEC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAajE;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,SAASC,kBACPC,QAAoC;QAErBA,kBACDA,iBACKA;IAFnB,MAAMC,UAASD,mBAAAA,SAASC,MAAM,YAAfD,mBAAmB;IAClC,MAAME,SAAQF,kBAAAA,SAASE,KAAK,YAAdF,kBAAkB;IAChC,MAAMG,cAAaH,uBAAAA,SAASG,UAAU,YAAnBH,uBAAuB;IAC1C,OAAQA,SAASI,IAAI;QACnB,KAAK;YACH,OAAO;gBACLC,UAAU;gBACVC,SAAS;oBAAEL;oBAAQM,UAAUJ;gBAAW;gBACxCK,MAAM;gBACNC,qBAAqB;YACvB;QACF,KAAK;YACH,OAAO;gBACLJ,UAAU;gBACVC,SAAS;oBAAEL;oBAAQS,aAAaP;gBAAW;gBAC3CK,MAAM;YACR;QACF,KAAK;YACH,OAAO;gBACLH,UAAU;gBACVC,SAAS;oBAAEL;gBAAO;gBAClBO,MAAM;YACR;QACF,KAAK;YACH,OAAO;gBACLH,UAAU;gBACVC,SAAS;oBAAEL;gBAAO;gBAClBO,MAAM;YACR;QACF,yEAAyE;QACzE,KAAK;YACH,OAAO;gBACLH,UAAU;gBACVC,SAAS;oBAAEJ;oBAAOS,WAAWR;gBAAW;gBACxCK,MAAM;YACR;QACF,KAAK;YACH,OAAO;gBACLH,UAAU;gBACVC,SAAS;oBAAEL;oBAAQW,aAAaT;gBAAW;gBAC3CK,MAAM;YACR;QACF,KAAK;YACH,OAAO;gBACLH,UAAU;gBACVC,SAAS;oBAAEL;oBAAQY,UAAUV;gBAAW;gBACxCK,MAAM;YACR;QACF;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASM,sBAAsB,EACpCd,QAAQ,EACRe,OAAO,EACyB;4BAmJpBjC;IAlJZ,uEAAuE;IACvE,iEAAiE;IACjE,MAAMkC,SAASnB,QACb,IAAOG,WAAWD,kBAAkBC,YAAY,MAChD;QAACA;KAAS;IAEZ,MAAM,EAAEiB,MAAMC,IAAI,EAAE,GAAGjC;IACvB,MAAM,EAAEkC,eAAe,EAAE,GAAGnC;IAC5B,MAAM,CAACoC,MAAMC,QAAQ,GAAGvB,SAAS;IACjC,MAAM,CAACwB,aAAaC,eAAe,GAAGzB,SAAS;IAC/C,MAAM,CAAC0B,UAAUC,YAAY,GAAG3B,SAAS;IACzC,MAAM,CAAC4B,OAAOC,SAAS,GAAG7B,SAAS;IACnC,MAAM,CAAC8B,MAAMC,QAAQ,GAAG/B,SAAS;IAEjCF,UAAU;YAEAI,uBACOA;QAFf,IAAI,CAACA,UAAU;QACfqB,SAAQrB,wBAAAA,SAAS8B,WAAW,YAApB9B,wBAAwB;QAChCuB,gBAAevB,wBAAAA,SAASsB,WAAW,YAApBtB,wBAAwB;QACvCyB,YAAY;QACZE,SAAS;IACX,GAAG;QAAC3B;KAAS;IAEb,MAAM+B,gBAAgBpC,YAAY;QAChC,IAAI,CAACqB,UAAU,CAACI,KAAKY,IAAI,MAAMJ,MAAM;QACrCC,QAAQ;QACR,IAAI;YACF,MAAMI,WAAW,MAAM/C,gBAAgBgC,MAAM,CAAC,KAAK,EAAEF,OAAOX,QAAQ,EAAE,EAAE;gBACtE6B,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;gBAAmB;gBAC9CC,MAAMC,KAAKC,SAAS,CAAC,aAChBtB,OAAOV,OAAO;oBACjBwB,aAAaV,KAAKY,IAAI;oBACtBV,aAAaA,YAAYU,IAAI;oBAC7BR,UAAUA,SAASQ,IAAI;oBACvBO,UAAUC,OAAOd,UAAU;;YAE/B;YACA,MAAMpB,UAAU,MAAM2B,SAASQ,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACpD,IAAI,CAACT,SAASU,EAAE,EAAE;;gBAChB,mEAAmE;gBACnE,6DAA6D;gBAC7D,OAAO,KAAKxB,wBAAgBb,2BAAAA,QAASsC,KAAK,mBAAI,kBAAkB;oBAC9DC,SAASZ,SAASa,MAAM,KAAK,MAAM,YAAY;oBAC/CC,gBAAgB;gBAClB;YACF;YACA5B,gBAAgB,CAAC,WAAW,EAAEb,QAAQ0C,OAAO,CAAC,mBAAmB,CAAC,EAAE;gBAClEH,SAAS;gBACTI,SAAS;YACX;YACAlC;QACF,EAAE,OAAO6B,OAAO;YACdM,QAAQN,KAAK,CAACA;YACdzB,gBAAgB,yBAAyB;gBACvC0B,SAAS;gBACTE,gBAAgB;YAClB;QACF,SAAU;YACRlB,QAAQ;QACV;IACF,GAAG;QACDb;QACAI;QACAE;QACAE;QACAE;QACAE;QACAV;QACAC;QACAJ;KACD;IAED,IAAIf,YAAY,CAACgB,QAAQ;QACvB,qBACE,MAAC5B;YAAO+D,IAAI;YAACpC,SAASA;YAASqC,UAAS;YAAKC,SAAS;;8BACpD,KAAC9D;8BAAa;;8BACd,KAACD;8BACC,cAAA,KAACI;wBAAWmD,SAAQ;wBAAQS,OAAM;kCAC/B,CAAC,oCAAoC,EAAEtD,SAASI,IAAI,CAAC,WAAW,CAAC,GAChE;;;8BAGN,KAACf;8BACC,cAAA,KAACF;wBAAOoE,MAAK;wBAAQC,SAASzC;kCAC3B;;;;;IAKX;IAEA,qBACE,MAAC3B;QACC+D,MAAM,CAAC,CAACnC;QACRD,SAASa,OAAO6B,YAAY1C;QAC5BqC,UAAS;QACTC,SAAS;;0BAET,KAAC9D;0BAAa,CAAC,QAAQ,UAAEyB,0BAAAA,OAAQR,IAAI,mBAAI,YAAY;;0BACrD,KAAClB;0BACC,cAAA,MAACE;oBAAMkE,SAAS;oBAAGC,IAAI;wBAAEC,IAAI;oBAAE;;sCAC7B,KAAClE;4BAAWmD,SAAQ;4BAAQS,OAAM;sCAC/B,CAAC,gDAAgD,CAAC,GACjD,YAAGtC,0BAAAA,OAAQR,IAAI,oBAAI,WAAW,4BAA4B,CAAC,GAC3D;;sCAEJ,KAACf;4BACCoE,SAAS;4BACTN,MAAK;4BACLO,OAAM;4BACNC,OAAO3C;4BACP4C,UAAU,CAACC,QAAU5C,QAAQ4C,MAAMjD,MAAM,CAAC+C,KAAK;4BAC/CG,UAAUtC;4BACVyB,SAAS;;sCAEX,KAAC5D;4BACC8D,MAAK;4BACLO,OAAM;4BACNC,OAAOzC;4BACP0C,UAAU,CAACC,QAAU1C,eAAe0C,MAAMjD,MAAM,CAAC+C,KAAK;4BACtDG,UAAUtC;4BACVuC,SAAS;4BACTC,SAAS;4BACTf,SAAS;;sCAEX,KAAC5D;4BACC8D,MAAK;4BACLO,OAAM;4BACNO,WAAW,WAAErD,0BAAAA,OAAQP,mBAAmB,oBAAI;4BAC5CsD,OAAOvC;4BACPwC,UAAU,CAACC,QAAUxC,YAAYwC,MAAMjD,MAAM,CAAC+C,KAAK;4BACnDG,UAAUtC;4BACVyB,SAAS;;sCAEX,KAAC5D;4BACC8D,MAAK;4BACLO,OAAM;4BACNO,aAAY;4BACZ,0DAA0D;4BAC1D,kEAAkE;4BAClE,oEAAoE;4BACpE,+DAA+D;4BAC/D,oEAAoE;4BACpE,6CAA6C;4BAC7CzB,OAAO/D,6BAA6B6C;4BACpC4C,UAAU,GACRxF,4BAAAA,yBAAyB4C,kBAAzB5C,4BACAC,0BACE;4BAGJgF,OAAOrC;4BACPsC,UAAU,CAACC,QACTtC,SAASsC,MAAMjD,MAAM,CAAC+C,KAAK,CAACQ,OAAO,CAAC,WAAW;4BAEjDL,UAAUtC;4BACVyB,SAAS;;;;;0BAIf,MAAChE;;kCACC,KAACF;wBAAOoE,MAAK;wBAAQC,SAASzC;wBAASmD,UAAUtC;kCAC9C;;kCAEH,KAACzC;wBACCoE,MAAK;wBACLV,SAAQ;wBACRS,OAAM;wBACNY,UAAUtC,QAAQ,CAACR,KAAKY,IAAI,MAAMnD,6BAA6B6C;wBAC/D8B,SAAS,IAAM,KAAKzB;kCAEnBH,OAAO,gBAAgB;;;;;;AAKlC;AAEAd,sBAAsBgB,WAAW,GAAG;AAEpC,eAAehB,sBAAqB"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -19,6 +19,7 @@ import MarketplaceBrowse from "./components/marketplace-browse.component.js";
|
|
|
19
19
|
import MarketplacePaymentsNotice from "./components/marketplace-payments-notice.component.js";
|
|
20
20
|
import HostPluginsCard from "./components/host-plugins-card.component.js";
|
|
21
21
|
import PluginSiteSetPanel from "./components/plugin-site-set-panel.component.js";
|
|
22
|
+
import PublishArtifactDialog from "./components/publish-artifact-dialog.component.js";
|
|
22
23
|
import { MarketplaceListingContent } from "./components/listing-content.component.js";
|
|
23
24
|
import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
24
25
|
import { RATING_FIELD } from "./model/rating-field.js";
|
|
@@ -83,6 +84,16 @@ import RatingInput from "./components/rating-input.component.js";
|
|
|
83
84
|
slot: 'pluginSiteSet',
|
|
84
85
|
widgetId: 'marketplace-plugin-site-set',
|
|
85
86
|
Component: PluginSiteSetPanel
|
|
87
|
+
},
|
|
88
|
+
// Publishing something the console holds (AGL-3080). The page that
|
|
89
|
+
// offers it keeps the control that opens it — a menu item is one entry
|
|
90
|
+
// of a list the page builds, not a widget — and hands over what it has
|
|
91
|
+
// in its own vocabulary. Where a layout or a theme GOES, what a listing
|
|
92
|
+
// of it is called and what it may cost at the least are this plugin's.
|
|
93
|
+
{
|
|
94
|
+
slot: 'hostArtifactPublish',
|
|
95
|
+
widgetId: 'marketplace-publish-artifact',
|
|
96
|
+
Component: PublishArtifactDialog
|
|
86
97
|
}
|
|
87
98
|
],
|
|
88
99
|
pluginId: BUNDLE_ID,
|
package/src/lib/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport MarketplaceBrowse from './components/marketplace-browse.component'\nimport MarketplacePaymentsNotice from './components/marketplace-payments-notice.component'\nimport HostPluginsCard from './components/host-plugins-card.component'\nimport PluginSiteSetPanel from './components/plugin-site-set-panel.component'\nimport { MarketplaceListingContent } from './components/listing-content.component'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { RATING_FIELD } from './model/rating-field'\nimport RatingInput from './components/rating-input.component'\n\n/**\n * Marketplace feature plugin (AGL-395). Console-only — marketplace components\n * install into a host's own components collection and render through the\n * normal compose pipeline, so there is no separate canvas bundle.\n *\n * The marketplace moved to org scope (AGL-772/774): browse + install live at\n * `/[orgSlug]/marketplace`, so this plugin no longer contributes a per-site\n * `Marketplace` nav tab (AGL-775). It exposes its UI purely through widget\n * slots — `orgMarketplace` (browse), `marketplaceListing` (detail) and\n * `orgAddons` (installed) — which the app renders without importing the\n * plugin.\n */\nexport function registerMarketplaceConsole(): void {\n // Custom field type (AGL-434): rating rides int32 with a starred input.\n Aglyn.registerCustomFieldType({ ...RATING_FIELD, Input: RatingInput })\n Aglyn.registerConsoleExtension({\n // Listing detail content (AGL-419): the app route keeps the chrome\n // and renders this through the 'marketplaceListing' slot.\n widgets: [\n {\n slot: 'marketplaceListing',\n widgetId: 'marketplace-listing-content',\n Component: MarketplaceListingContent,\n },\n // What this deployment cannot do, said BEFORE the click (AGL-2019,\n // moved here by AGL-3080). The sentence names what still works\n // without a Stripe platform — browsing and free installs — which is\n // this plugin's knowledge; the app supplies only the fact, through\n // the deployment-capability context its org layout provides. The\n // widget draws nothing at all on a configured deployment.\n {\n slot: 'marketplaceCapability',\n widgetId: 'marketplace-payments-notice',\n Component: MarketplacePaymentsNotice,\n },\n // Org marketplace browse (AGL-772): the org-scope `/marketplace`\n // page renders this with an acting hostId + orgScoped, so listing\n // links resolve to the org route. The single place to browse/install,\n // replacing the per-site marketplace tab.\n {\n slot: 'orgMarketplace',\n widgetId: 'marketplace-org-marketplace',\n Component: MarketplaceBrowse,\n },\n // Installed add-ons management (AGL-423): the org \"Plugins &\n // add-ons\" hub renders this with an acting hostId — the card lists\n // host + org install pins with upgrade/uninstall/share-with-org.\n {\n slot: 'orgAddons',\n widgetId: 'marketplace-installed-addons',\n Component: HostPluginsCard,\n },\n // The site set for one installation (AGL-1007): the same control the\n // listing page uses, exposed so the installation detail page can show\n // it without the app importing this plugin.\n {\n slot: 'pluginSiteSet',\n widgetId: 'marketplace-plugin-site-set',\n Component: PluginSiteSetPanel,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Marketplace',\n })\n}\n\n// Shared with the listing/publisher detail app-routes.\nexport { default as useMarketplaceActions } from './hooks/use-marketplace-actions'\nexport { default as MarketplaceBrowse } from './components/marketplace-browse.component'\nexport { default as HostPluginsCard } from './components/host-plugins-card.component'\nexport { default as PluginSiteSetPanel } from './components/plugin-site-set-panel.component'\n"],"names":["Aglyn","MarketplaceBrowse","MarketplacePaymentsNotice","HostPluginsCard","PluginSiteSetPanel","MarketplaceListingContent","BUNDLE_ID","RATING_FIELD","RatingInput","registerMarketplaceConsole","registerCustomFieldType","Input","registerConsoleExtension","widgets","slot","widgetId","Component","pluginId","displayName","default","useMarketplaceActions"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,OAAOC,uBAAuB,+CAA2C;AACzE,OAAOC,+BAA+B,wDAAoD;AAC1F,OAAOC,qBAAqB,8CAA0C;AACtE,OAAOC,wBAAwB,kDAA8C;AAC7E,SAASC,yBAAyB,QAAQ,4CAAwC;AAClF,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,YAAY,QAAQ,0BAAsB;AACnD,OAAOC,iBAAiB,yCAAqC;AAE7D;;;;;;;;;;;CAWC,GACD,OAAO,SAASC;IACd,wEAAwE;
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport MarketplaceBrowse from './components/marketplace-browse.component'\nimport MarketplacePaymentsNotice from './components/marketplace-payments-notice.component'\nimport HostPluginsCard from './components/host-plugins-card.component'\nimport PluginSiteSetPanel from './components/plugin-site-set-panel.component'\nimport PublishArtifactDialog from './components/publish-artifact-dialog.component'\nimport { MarketplaceListingContent } from './components/listing-content.component'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { RATING_FIELD } from './model/rating-field'\nimport RatingInput from './components/rating-input.component'\n\n/**\n * Marketplace feature plugin (AGL-395). Console-only — marketplace components\n * install into a host's own components collection and render through the\n * normal compose pipeline, so there is no separate canvas bundle.\n *\n * The marketplace moved to org scope (AGL-772/774): browse + install live at\n * `/[orgSlug]/marketplace`, so this plugin no longer contributes a per-site\n * `Marketplace` nav tab (AGL-775). It exposes its UI purely through widget\n * slots — `orgMarketplace` (browse), `marketplaceListing` (detail) and\n * `orgAddons` (installed) — which the app renders without importing the\n * plugin.\n */\nexport function registerMarketplaceConsole(): void {\n // Custom field type (AGL-434): rating rides int32 with a starred input.\n Aglyn.registerCustomFieldType({ ...RATING_FIELD, Input: RatingInput })\n Aglyn.registerConsoleExtension({\n // Listing detail content (AGL-419): the app route keeps the chrome\n // and renders this through the 'marketplaceListing' slot.\n widgets: [\n {\n slot: 'marketplaceListing',\n widgetId: 'marketplace-listing-content',\n Component: MarketplaceListingContent,\n },\n // What this deployment cannot do, said BEFORE the click (AGL-2019,\n // moved here by AGL-3080). The sentence names what still works\n // without a Stripe platform — browsing and free installs — which is\n // this plugin's knowledge; the app supplies only the fact, through\n // the deployment-capability context its org layout provides. The\n // widget draws nothing at all on a configured deployment.\n {\n slot: 'marketplaceCapability',\n widgetId: 'marketplace-payments-notice',\n Component: MarketplacePaymentsNotice,\n },\n // Org marketplace browse (AGL-772): the org-scope `/marketplace`\n // page renders this with an acting hostId + orgScoped, so listing\n // links resolve to the org route. The single place to browse/install,\n // replacing the per-site marketplace tab.\n {\n slot: 'orgMarketplace',\n widgetId: 'marketplace-org-marketplace',\n Component: MarketplaceBrowse,\n },\n // Installed add-ons management (AGL-423): the org \"Plugins &\n // add-ons\" hub renders this with an acting hostId — the card lists\n // host + org install pins with upgrade/uninstall/share-with-org.\n {\n slot: 'orgAddons',\n widgetId: 'marketplace-installed-addons',\n Component: HostPluginsCard,\n },\n // The site set for one installation (AGL-1007): the same control the\n // listing page uses, exposed so the installation detail page can show\n // it without the app importing this plugin.\n {\n slot: 'pluginSiteSet',\n widgetId: 'marketplace-plugin-site-set',\n Component: PluginSiteSetPanel,\n },\n // Publishing something the console holds (AGL-3080). The page that\n // offers it keeps the control that opens it — a menu item is one entry\n // of a list the page builds, not a widget — and hands over what it has\n // in its own vocabulary. Where a layout or a theme GOES, what a listing\n // of it is called and what it may cost at the least are this plugin's.\n {\n slot: 'hostArtifactPublish',\n widgetId: 'marketplace-publish-artifact',\n Component: PublishArtifactDialog,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Marketplace',\n })\n}\n\n// Shared with the listing/publisher detail app-routes.\nexport { default as useMarketplaceActions } from './hooks/use-marketplace-actions'\nexport { default as MarketplaceBrowse } from './components/marketplace-browse.component'\nexport { default as HostPluginsCard } from './components/host-plugins-card.component'\nexport { default as PluginSiteSetPanel } from './components/plugin-site-set-panel.component'\n"],"names":["Aglyn","MarketplaceBrowse","MarketplacePaymentsNotice","HostPluginsCard","PluginSiteSetPanel","PublishArtifactDialog","MarketplaceListingContent","BUNDLE_ID","RATING_FIELD","RatingInput","registerMarketplaceConsole","registerCustomFieldType","Input","registerConsoleExtension","widgets","slot","widgetId","Component","pluginId","displayName","default","useMarketplaceActions"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,OAAOC,uBAAuB,+CAA2C;AACzE,OAAOC,+BAA+B,wDAAoD;AAC1F,OAAOC,qBAAqB,8CAA0C;AACtE,OAAOC,wBAAwB,kDAA8C;AAC7E,OAAOC,2BAA2B,oDAAgD;AAClF,SAASC,yBAAyB,QAAQ,4CAAwC;AAClF,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,YAAY,QAAQ,0BAAsB;AACnD,OAAOC,iBAAiB,yCAAqC;AAE7D;;;;;;;;;;;CAWC,GACD,OAAO,SAASC;IACd,wEAAwE;IACxEV,MAAMW,uBAAuB,CAAC,aAAKH;QAAcI,OAAOH;;IACxDT,MAAMa,wBAAwB,CAAC;QAC7B,mEAAmE;QACnE,0DAA0D;QAC1DC,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVC,WAAWX;YACb;YACA,mEAAmE;YACnE,+DAA+D;YAC/D,oEAAoE;YACpE,mEAAmE;YACnE,iEAAiE;YACjE,0DAA0D;YAC1D;gBACES,MAAM;gBACNC,UAAU;gBACVC,WAAWf;YACb;YACA,iEAAiE;YACjE,kEAAkE;YAClE,sEAAsE;YACtE,0CAA0C;YAC1C;gBACEa,MAAM;gBACNC,UAAU;gBACVC,WAAWhB;YACb;YACA,6DAA6D;YAC7D,mEAAmE;YACnE,iEAAiE;YACjE;gBACEc,MAAM;gBACNC,UAAU;gBACVC,WAAWd;YACb;YACA,qEAAqE;YACrE,sEAAsE;YACtE,4CAA4C;YAC5C;gBACEY,MAAM;gBACNC,UAAU;gBACVC,WAAWb;YACb;YACA,mEAAmE;YACnE,uEAAuE;YACvE,uEAAuE;YACvE,wEAAwE;YACxE,uEAAuE;YACvE;gBACEW,MAAM;gBACNC,UAAU;gBACVC,WAAWZ;YACb;SACD;QACDa,UAAUX;QACVY,aAAa;IACf;AACF;AAEA,uDAAuD;AACvD,SAASC,WAAWC,qBAAqB,QAAQ,qCAAiC;AAClF,SAASD,WAAWnB,iBAAiB,QAAQ,+CAA2C;AACxF,SAASmB,WAAWjB,eAAe,QAAQ,8CAA0C;AACrF,SAASiB,WAAWhB,kBAAkB,QAAQ,kDAA8C"}
|