@aglyn/plugins-marketplace 1.0.0-beta.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +51 -0
  4. package/src/index.d.ts +19 -0
  5. package/src/index.js +20 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/artifact-update-dialog.component.d.ts +27 -0
  8. package/src/lib/components/artifact-update-dialog.component.js +244 -0
  9. package/src/lib/components/artifact-update-dialog.component.js.map +1 -0
  10. package/src/lib/components/host-plugins-card.component.d.ts +23 -0
  11. package/src/lib/components/host-plugins-card.component.js +566 -0
  12. package/src/lib/components/host-plugins-card.component.js.map +1 -0
  13. package/src/lib/components/listing-content.component.d.ts +57 -0
  14. package/src/lib/components/listing-content.component.js +1880 -0
  15. package/src/lib/components/listing-content.component.js.map +1 -0
  16. package/src/lib/components/listing-image.component.d.ts +46 -0
  17. package/src/lib/components/listing-image.component.js +38 -0
  18. package/src/lib/components/listing-image.component.js.map +1 -0
  19. package/src/lib/components/listing-reviews.component.d.ts +22 -0
  20. package/src/lib/components/listing-reviews.component.js +419 -0
  21. package/src/lib/components/listing-reviews.component.js.map +1 -0
  22. package/src/lib/components/marketplace-browse.component.d.ts +38 -0
  23. package/src/lib/components/marketplace-browse.component.js +802 -0
  24. package/src/lib/components/marketplace-browse.component.js.map +1 -0
  25. package/src/lib/components/plugin-site-set-panel.component.d.ts +24 -0
  26. package/src/lib/components/plugin-site-set-panel.component.js +137 -0
  27. package/src/lib/components/plugin-site-set-panel.component.js.map +1 -0
  28. package/src/lib/components/plugin-site-set.component.d.ts +43 -0
  29. package/src/lib/components/plugin-site-set.component.js +425 -0
  30. package/src/lib/components/plugin-site-set.component.js.map +1 -0
  31. package/src/lib/components/rating-input.component.d.ts +3 -0
  32. package/src/lib/components/rating-input.component.js +47 -0
  33. package/src/lib/components/rating-input.component.js.map +1 -0
  34. package/src/lib/components/report-target.component.d.ts +36 -0
  35. package/src/lib/components/report-target.component.js +181 -0
  36. package/src/lib/components/report-target.component.js.map +1 -0
  37. package/src/lib/components/uninstall-impact-dialog.component.d.ts +40 -0
  38. package/src/lib/components/uninstall-impact-dialog.component.js +244 -0
  39. package/src/lib/components/uninstall-impact-dialog.component.js.map +1 -0
  40. package/src/lib/constants/bundle-common.d.ts +8 -0
  41. package/src/lib/constants/bundle-common.js +9 -0
  42. package/src/lib/constants/bundle-common.js.map +1 -0
  43. package/src/lib/hooks/use-artifact-update.d.ts +41 -0
  44. package/src/lib/hooks/use-artifact-update.js +169 -0
  45. package/src/lib/hooks/use-artifact-update.js.map +1 -0
  46. package/src/lib/hooks/use-marketplace-actions.d.ts +37 -0
  47. package/src/lib/hooks/use-marketplace-actions.js +523 -0
  48. package/src/lib/hooks/use-marketplace-actions.js.map +1 -0
  49. package/src/lib/model/artifact-merge.d.ts +154 -0
  50. package/src/lib/model/artifact-merge.js +228 -0
  51. package/src/lib/model/artifact-merge.js.map +1 -0
  52. package/src/lib/model/index.d.ts +43 -0
  53. package/src/lib/model/index.js +41 -0
  54. package/src/lib/model/index.js.map +1 -0
  55. package/src/lib/model/marketplace-props.d.ts +57 -0
  56. package/src/lib/model/marketplace-props.js +441 -0
  57. package/src/lib/model/marketplace-props.js.map +1 -0
  58. package/src/lib/model/marketplace.d.ts +833 -0
  59. package/src/lib/model/marketplace.js +929 -0
  60. package/src/lib/model/marketplace.js.map +1 -0
  61. package/src/lib/model/rating-field.d.ts +24 -0
  62. package/src/lib/model/rating-field.js +33 -0
  63. package/src/lib/model/rating-field.js.map +1 -0
  64. package/src/lib/plugin.d.ts +33 -0
  65. package/src/lib/plugin.js +86 -0
  66. package/src/lib/plugin.js.map +1 -0
  67. package/src/lib/server/billing-webhook.d.ts +25 -0
  68. package/src/lib/server/billing-webhook.js +1062 -0
  69. package/src/lib/server/billing-webhook.js.map +1 -0
  70. package/src/lib/server/checkout.d.ts +76 -0
  71. package/src/lib/server/checkout.js +477 -0
  72. package/src/lib/server/checkout.js.map +1 -0
  73. package/src/lib/server/connect.d.ts +24 -0
  74. package/src/lib/server/connect.js +205 -0
  75. package/src/lib/server/connect.js.map +1 -0
  76. package/src/lib/server/install-dataset-schema.d.ts +32 -0
  77. package/src/lib/server/install-dataset-schema.js +255 -0
  78. package/src/lib/server/install-dataset-schema.js.map +1 -0
  79. package/src/lib/server/install-email-starter.d.ts +65 -0
  80. package/src/lib/server/install-email-starter.js +279 -0
  81. package/src/lib/server/install-email-starter.js.map +1 -0
  82. package/src/lib/server/install-email-template.d.ts +34 -0
  83. package/src/lib/server/install-email-template.js +252 -0
  84. package/src/lib/server/install-email-template.js.map +1 -0
  85. package/src/lib/server/install-layout.d.ts +29 -0
  86. package/src/lib/server/install-layout.js +323 -0
  87. package/src/lib/server/install-layout.js.map +1 -0
  88. package/src/lib/server/install-pin-counts.d.ts +173 -0
  89. package/src/lib/server/install-pin-counts.js +248 -0
  90. package/src/lib/server/install-pin-counts.js.map +1 -0
  91. package/src/lib/server/install-plugin.d.ts +18 -0
  92. package/src/lib/server/install-plugin.js +405 -0
  93. package/src/lib/server/install-plugin.js.map +1 -0
  94. package/src/lib/server/install-template.d.ts +37 -0
  95. package/src/lib/server/install-template.js +348 -0
  96. package/src/lib/server/install-template.js.map +1 -0
  97. package/src/lib/server/install-theme.d.ts +42 -0
  98. package/src/lib/server/install-theme.js +313 -0
  99. package/src/lib/server/install-theme.js.map +1 -0
  100. package/src/lib/server/install.d.ts +27 -0
  101. package/src/lib/server/install.js +276 -0
  102. package/src/lib/server/install.js.map +1 -0
  103. package/src/lib/server/listing-versions.d.ts +26 -0
  104. package/src/lib/server/listing-versions.js +378 -0
  105. package/src/lib/server/listing-versions.js.map +1 -0
  106. package/src/lib/server/preview-image.d.ts +37 -0
  107. package/src/lib/server/preview-image.js +216 -0
  108. package/src/lib/server/preview-image.js.map +1 -0
  109. package/src/lib/server/provenance.d.ts +100 -0
  110. package/src/lib/server/provenance.js +118 -0
  111. package/src/lib/server/provenance.js.map +1 -0
  112. package/src/lib/server/publish-dataset-schema.d.ts +31 -0
  113. package/src/lib/server/publish-dataset-schema.js +202 -0
  114. package/src/lib/server/publish-dataset-schema.js.map +1 -0
  115. package/src/lib/server/publish-email-starter.d.ts +44 -0
  116. package/src/lib/server/publish-email-starter.js +231 -0
  117. package/src/lib/server/publish-email-starter.js.map +1 -0
  118. package/src/lib/server/publish-email-template.d.ts +33 -0
  119. package/src/lib/server/publish-email-template.js +211 -0
  120. package/src/lib/server/publish-email-template.js.map +1 -0
  121. package/src/lib/server/publish-layout.d.ts +33 -0
  122. package/src/lib/server/publish-layout.js +243 -0
  123. package/src/lib/server/publish-layout.js.map +1 -0
  124. package/src/lib/server/publish-plugin.d.ts +18 -0
  125. package/src/lib/server/publish-plugin.js +485 -0
  126. package/src/lib/server/publish-plugin.js.map +1 -0
  127. package/src/lib/server/publish-preconditions.d.ts +86 -0
  128. package/src/lib/server/publish-preconditions.js +160 -0
  129. package/src/lib/server/publish-preconditions.js.map +1 -0
  130. package/src/lib/server/publish-template.d.ts +27 -0
  131. package/src/lib/server/publish-template.js +215 -0
  132. package/src/lib/server/publish-template.js.map +1 -0
  133. package/src/lib/server/publish-theme.d.ts +38 -0
  134. package/src/lib/server/publish-theme.js +186 -0
  135. package/src/lib/server/publish-theme.js.map +1 -0
  136. package/src/lib/server/publish.d.ts +26 -0
  137. package/src/lib/server/publish.js +204 -0
  138. package/src/lib/server/publish.js.map +1 -0
  139. package/src/lib/server/publisher-profile-save.d.ts +30 -0
  140. package/src/lib/server/publisher-profile-save.js +226 -0
  141. package/src/lib/server/publisher-profile-save.js.map +1 -0
  142. package/src/lib/server/publisher-profile.d.ts +86 -0
  143. package/src/lib/server/publisher-profile.js +116 -0
  144. package/src/lib/server/publisher-profile.js.map +1 -0
  145. package/src/lib/server/purchase-entitlement.d.ts +83 -0
  146. package/src/lib/server/purchase-entitlement.js +118 -0
  147. package/src/lib/server/purchase-entitlement.js.map +1 -0
  148. package/src/lib/server/report.d.ts +32 -0
  149. package/src/lib/server/report.js +101 -0
  150. package/src/lib/server/report.js.map +1 -0
  151. package/src/lib/server/reviews.d.ts +41 -0
  152. package/src/lib/server/reviews.js +240 -0
  153. package/src/lib/server/reviews.js.map +1 -0
  154. package/src/lib/server/update-artifact.d.ts +19 -0
  155. package/src/lib/server/update-artifact.js +569 -0
  156. package/src/lib/server/update-artifact.js.map +1 -0
  157. package/src/lib/server/verification-request.d.ts +31 -0
  158. package/src/lib/server/verification-request.js +173 -0
  159. package/src/lib/server/verification-request.js.map +1 -0
  160. package/src/lib/server/version-stats.d.ts +202 -0
  161. package/src/lib/server/version-stats.js +305 -0
  162. package/src/lib/server/version-stats.js.map +1 -0
  163. package/src/lib/server.d.ts +30 -0
  164. package/src/lib/server.js +95 -0
  165. package/src/lib/server.js.map +1 -0
@@ -0,0 +1,566 @@
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 { buildRoute, PLUGIN_COMPONENT_ID, pluginDocsHelp, Route } from "@aglyn/aglyn";
20
+ import { AppLink, CardDisplay, useConfirmationContext } from "@aglyn/shared-ui-jsx";
21
+ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
22
+ import { Alert, Button, Chip, Stack, Tooltip, Typography } from "@mui/material";
23
+ import { collection, deleteDoc, doc, documentId, limit, query, where } from "firebase/firestore";
24
+ import { useCallback, useMemo, useState } from "react";
25
+ import { compareArtifactVersions, isPluginRevoked, lockdownRefusalText, offeredPluginVersion, parseLockdownRefusal } from "@aglyn/aglyn";
26
+ import { useFirestore, useFirestoreCollection, useHostOrgId, useUser } from "@aglyn/tenant-feature-instance";
27
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
28
+ /**
29
+ * Installed marketplace plugins (AGL-45): lists the host's pinned plugin
30
+ * installs with their capabilities, flags available upgrades (latest
31
+ * listing version ≠ pinned) and platform kill switches (public
32
+ * `revocations` read), and offers explicit upgrade/uninstall. Upgrades go
33
+ * through `/api/marketplace/install-plugin` so the new pin is validated
34
+ * server-side; uninstall removes the host install doc. Place the installed
35
+ * plugin on a screen with the Plugin element (listing id).
36
+ */ export function HostPluginsCard(props) {
37
+ const { hostId, orgSlug } = props;
38
+ // One row → one installation page (AGL-1007). The name is the link, so a
39
+ // row stays clickable without swallowing its own action buttons.
40
+ const installationHref = (listingId)=>orgSlug ? buildRoute(Route.ORG_PLUGIN_INSTALLATION, {
41
+ orgSlug,
42
+ pluginRef: listingId
43
+ }) : undefined;
44
+ const firestore = useFirestore();
45
+ const { data: user } = useUser();
46
+ const { enqueueSnackbar } = useSnackbar();
47
+ const { confirm } = useConfirmationContext();
48
+ const [busy, setBusy] = useState(null);
49
+ const orgId = useHostOrgId(hostId);
50
+ const { data: installDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'installs'), limit(50)), [
51
+ firestore,
52
+ hostId
53
+ ], {
54
+ idField: '$id'
55
+ });
56
+ // Org-tier pins (AGL-237): apply to every host in the org; a host pin
57
+ // of the same listing shadows the org one. Held at null while
58
+ // `useHostOrgId` is in flight, never `orgs/-pending-` (AGL-1440):
59
+ // installs are member-gated, so the sentinel was a guaranteed-denied
60
+ // listen on every mount of this card.
61
+ const { data: orgInstallDocs } = useFirestoreCollection(()=>orgId ? query(collection(firestore, 'orgs', orgId, 'installs'), limit(50)) : null, [
62
+ firestore,
63
+ orgId
64
+ ], {
65
+ idField: '$id'
66
+ });
67
+ const orgInstalls = useMemo(()=>[
68
+ ...orgInstallDocs != null ? orgInstallDocs : []
69
+ ], [
70
+ orgInstallDocs
71
+ ]);
72
+ const installs = useMemo(()=>[
73
+ ...installDocs != null ? installDocs : []
74
+ ], [
75
+ installDocs
76
+ ]);
77
+ const listingIds = useMemo(()=>[
78
+ ...new Set([
79
+ ...installs.map((install)=>install.$id),
80
+ ...orgInstalls.map((install)=>install.$id)
81
+ ])
82
+ ].slice(0, 10), [
83
+ installs,
84
+ orgInstalls
85
+ ]);
86
+ // Latest published version per listing (upgrade detection) — public read.
87
+ const { data: listingDocs } = useFirestoreCollection(()=>query(collection(firestore, 'marketplaceListings'), where(documentId(), 'in', listingIds.length ? listingIds : [
88
+ '-none-'
89
+ ])), [
90
+ firestore,
91
+ listingIds.join(',')
92
+ ], {
93
+ idField: '$id'
94
+ });
95
+ // Kill switches (public revocations read) for the installed listings.
96
+ const { data: revocationDocs } = useFirestoreCollection(()=>query(collection(firestore, 'revocations'), where(documentId(), 'in', listingIds.length ? listingIds : [
97
+ '-none-'
98
+ ])), [
99
+ firestore,
100
+ listingIds.join(',')
101
+ ], {
102
+ idField: '$id'
103
+ });
104
+ const revokedByListing = useMemo(()=>{
105
+ const map = {};
106
+ for (const install of installs){
107
+ const revocation = (revocationDocs != null ? revocationDocs : []).find((doc)=>doc.$id === install.$id);
108
+ if (!revocation) continue;
109
+ // THE SHARED PREDICATE, not a fourth copy of it (AGL-2305). This card
110
+ // carried a byte-for-byte duplicate of `isPluginRevoked`'s body, which
111
+ // is precisely what AGL-1085 collapsed three inline copies into one to
112
+ // stop: a reader that disagrees with the writer about this document's
113
+ // shape is how a kill switch silently stops killing. It happened to be
114
+ // correct; being correct today is not the property that matters.
115
+ map[install.$id] = isPluginRevoked(revocation, install.version);
116
+ }
117
+ return map;
118
+ }, [
119
+ installs,
120
+ revocationDocs
121
+ ]);
122
+ /*==========================================
123
+ * WHY IT WAS DISABLED (AGL-2328).
124
+ *
125
+ * Staff are REQUIRED to type a reason to revoke a plugin version — the
126
+ * route refuses without one — and until now the customer whose site the
127
+ * plugin stopped working on was shown a bare "disabled" chip and a generic
128
+ * paragraph. The reason was stored, in the same document this card already
129
+ * reads, one field away from the flag it renders. Every consumer of
130
+ * `revocations` reads `versions` and nothing else; the type's own comment
131
+ * calls `versions` "the ONLY field any reader consults", which was true and
132
+ * is the defect.
133
+ *
134
+ * Only the REASON and the DATE are surfaced. `revokedBy` is a staff uid and
135
+ * belongs in the audit log, not on a customer's screen.
136
+ *=========================================*/ const revocationDetailByListing = useMemo(()=>{
137
+ const map = {};
138
+ for (const doc of revocationDocs != null ? revocationDocs : []){
139
+ var _ref;
140
+ var _at_toMillis;
141
+ const at = doc.revokedAt;
142
+ map[doc.$id] = {
143
+ reason: typeof doc.reason === 'string' && doc.reason.trim() ? doc.reason.trim() : null,
144
+ atMs: (_ref = at == null ? void 0 : (_at_toMillis = at.toMillis) == null ? void 0 : _at_toMillis.call(at)) != null ? _ref : typeof (at == null ? void 0 : at.seconds) === 'number' ? at.seconds * 1000 : null
145
+ };
146
+ }
147
+ return map;
148
+ }, [
149
+ revocationDocs
150
+ ]);
151
+ // The newest INSTALLABLE version, not merely the newest approved one
152
+ // (AGL-1016, corrected by AGL-2368).
153
+ //
154
+ // Offering `latestVersion` here put an Upgrade button in front of every
155
+ // workspace the moment a publisher uploaded, and the install route then
156
+ // refused the click — AGL-966 only ever hands out reviewed bytes. The
157
+ // mirror fixed that and then reproduced it one state over: nothing cleared
158
+ // it when a version was revoked, so the Upgrade button pointed at bytes the
159
+ // kill switch had stopped. Every writer of the mirror now derives it from
160
+ // `newestInstallableVersion`, and this card holds the revocation document
161
+ // ALREADY — it is right there, feeding the disabled chip below — so it
162
+ // cross-checks rather than trusting a cache written by a separate,
163
+ // non-transactional write it can observe mid-flight.
164
+ const latestByListing = useMemo(()=>{
165
+ const map = {};
166
+ for (const listing of listingDocs != null ? listingDocs : []){
167
+ var _offeredPluginVersion;
168
+ const revocation = (revocationDocs != null ? revocationDocs : []).find((doc)=>doc.$id === listing.$id);
169
+ map[listing.$id] = (_offeredPluginVersion = offeredPluginVersion(listing, revocation)) != null ? _offeredPluginVersion : '';
170
+ }
171
+ return map;
172
+ }, [
173
+ listingDocs,
174
+ revocationDocs
175
+ ]);
176
+ const handleUpgrade = useCallback((install)=>async ()=>{
177
+ setBusy(install.$id);
178
+ try {
179
+ const response = await authorizedFetch(user, '/api/marketplace/install-plugin', {
180
+ method: 'POST',
181
+ headers: {
182
+ 'Content-Type': 'application/json'
183
+ },
184
+ body: JSON.stringify({
185
+ hostId,
186
+ listingId: install.$id
187
+ })
188
+ });
189
+ const payload = await response.json().catch(()=>({}));
190
+ if (response.ok) {
191
+ enqueueSnackbar(`Upgraded to ${payload.version}`, {
192
+ variant: 'success',
193
+ persist: false
194
+ });
195
+ } else {
196
+ // An installs lockdown refuses the upgrade route too (AGL-1532).
197
+ const locked = parseLockdownRefusal(response.status, payload);
198
+ if (locked) {
199
+ enqueueSnackbar(lockdownRefusalText(locked), {
200
+ variant: 'warning',
201
+ persist: true
202
+ });
203
+ } else {
204
+ var _ref;
205
+ enqueueSnackbar((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Upgrade failed', {
206
+ variant: 'error',
207
+ allowDuplicate: true
208
+ });
209
+ }
210
+ }
211
+ } finally{
212
+ setBusy(null);
213
+ }
214
+ }, [
215
+ hostId,
216
+ user,
217
+ enqueueSnackbar
218
+ ]);
219
+ const requestPluginApi = useCallback(async (body)=>{
220
+ const response = await authorizedFetch(user, '/api/marketplace/install-plugin', {
221
+ method: 'POST',
222
+ headers: {
223
+ 'Content-Type': 'application/json'
224
+ },
225
+ body: JSON.stringify(_extends({
226
+ hostId
227
+ }, body))
228
+ });
229
+ const payload = await response.json().catch(()=>({}));
230
+ if (!response.ok) {
231
+ var _ref;
232
+ // Every install-class action in this card funnels through here
233
+ // (share, org upgrade, uninstall at both scopes) — so does the
234
+ // pause notice (AGL-1532).
235
+ const locked = parseLockdownRefusal(response.status, payload);
236
+ if (locked) {
237
+ enqueueSnackbar(lockdownRefusalText(locked), {
238
+ variant: 'warning',
239
+ persist: true
240
+ });
241
+ return null;
242
+ }
243
+ enqueueSnackbar((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Plugin operation failed', {
244
+ variant: 'error',
245
+ allowDuplicate: true
246
+ });
247
+ return null;
248
+ }
249
+ return payload;
250
+ }, [
251
+ hostId,
252
+ user,
253
+ enqueueSnackbar
254
+ ]);
255
+ // Promote a host pin to the org tier (AGL-237): org pin first, then the
256
+ // host pin is removed — host pins shadow org ones in the loader.
257
+ const handleShareWithOrg = useCallback((install)=>async ()=>{
258
+ setBusy(install.$id);
259
+ try {
260
+ const payload = await requestPluginApi({
261
+ listingId: install.$id,
262
+ scope: 'org'
263
+ });
264
+ if (!payload) return;
265
+ await deleteDoc(doc(firestore, 'hosts', hostId, 'installs', install.$id));
266
+ enqueueSnackbar('Plugin now installed for the whole organization', {
267
+ variant: 'success',
268
+ persist: false
269
+ });
270
+ } finally{
271
+ setBusy(null);
272
+ }
273
+ }, [
274
+ requestPluginApi,
275
+ firestore,
276
+ hostId,
277
+ enqueueSnackbar
278
+ ]);
279
+ const handleOrgUpgrade = useCallback((install)=>async ()=>{
280
+ setBusy(install.$id);
281
+ try {
282
+ const payload = await requestPluginApi({
283
+ listingId: install.$id,
284
+ scope: 'org'
285
+ });
286
+ if (payload) {
287
+ enqueueSnackbar(`Upgraded to ${payload.version}`, {
288
+ variant: 'success',
289
+ persist: false
290
+ });
291
+ }
292
+ } finally{
293
+ setBusy(null);
294
+ }
295
+ }, [
296
+ requestPluginApi,
297
+ enqueueSnackbar
298
+ ]);
299
+ const handleOrgUninstall = useCallback((install)=>async ()=>{
300
+ var _install_displayName;
301
+ const confirmed = await confirm({
302
+ title: `Uninstall "${(_install_displayName = install.displayName) != null ? _install_displayName : install.$id}" org-wide?`,
303
+ description: 'Every site in the organization loses this plugin unless it has ' + 'its own host-level pin. Data the plugin created stays untouched.',
304
+ confirmationText: 'Uninstall',
305
+ confirmationButtonProps: {
306
+ color: 'error'
307
+ }
308
+ }).then(()=>true).catch(()=>false);
309
+ if (!confirmed) return;
310
+ const payload = await requestPluginApi({
311
+ listingId: install.$id,
312
+ scope: 'org',
313
+ action: 'uninstall'
314
+ });
315
+ if (payload) {
316
+ enqueueSnackbar('Plugin uninstalled org-wide', {
317
+ variant: 'success',
318
+ persist: false
319
+ });
320
+ }
321
+ }, [
322
+ confirm,
323
+ requestPluginApi,
324
+ enqueueSnackbar
325
+ ]);
326
+ const handleUninstall = useCallback((install)=>async ()=>{
327
+ var _install_displayName;
328
+ const confirmed = await confirm({
329
+ title: `Uninstall "${(_install_displayName = install.displayName) != null ? _install_displayName : install.$id}"?`,
330
+ description: 'Plugin elements pointing at it will show a placeholder until ' + 'reinstalled. Data the plugin created stays untouched.',
331
+ confirmationText: 'Uninstall',
332
+ confirmationButtonProps: {
333
+ color: 'error'
334
+ }
335
+ }).then(()=>true).catch(()=>false);
336
+ if (!confirmed) return;
337
+ // Through the API (AGL-424) so the org enablement switchboard stays
338
+ // in step with the removed pin.
339
+ const payload = await requestPluginApi({
340
+ listingId: install.$id,
341
+ action: 'uninstall'
342
+ });
343
+ if (payload) {
344
+ enqueueSnackbar('Plugin uninstalled', {
345
+ variant: 'success',
346
+ persist: false
347
+ });
348
+ }
349
+ }, [
350
+ confirm,
351
+ requestPluginApi,
352
+ enqueueSnackbar
353
+ ]);
354
+ return /*#__PURE__*/ _jsx(CardDisplay, {
355
+ header: "Marketplace installs",
356
+ help: pluginDocsHelp('plugins', {
357
+ anchor: '#install--upgrade'
358
+ }),
359
+ contentGutterX: true,
360
+ contentGutterY: true,
361
+ children: /*#__PURE__*/ _jsxs(Stack, {
362
+ spacing: 1.5,
363
+ children: [
364
+ installs.length === 0 && orgInstalls.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
365
+ variant: "body2",
366
+ color: "text.secondary",
367
+ children: 'No marketplace plugins installed. Install one from the ' + 'marketplace, then add a Plugin element to a screen and set ' + 'its listing id.'
368
+ }) : installs.map((install)=>{
369
+ var _compareArtifactVersions, _ref, _ref1, _install_displayName, _ref2, _install_displayName1;
370
+ var _install_manifest, _capabilities_network, _capabilities_events, _capabilities_network1, _capabilities_events1, _revocationDetailByListing_install_$id, _revocationDetailByListing_install_$id1, _revocationDetailByListing_install_$id2, _revocationDetailByListing_install_$id3;
371
+ const latest = latestByListing[install.$id];
372
+ const canUpgrade = ((_compareArtifactVersions = compareArtifactVersions(install.version, latest)) != null ? _compareArtifactVersions : 0) < 0;
373
+ const revoked = revokedByListing[install.$id];
374
+ const capabilities = (_ref = (_install_manifest = install.manifest) == null ? void 0 : _install_manifest.capabilities) != null ? _ref : {};
375
+ return /*#__PURE__*/ _jsxs(Stack, {
376
+ spacing: 0.5,
377
+ sx: {
378
+ border: '1px solid',
379
+ borderColor: 'divider',
380
+ borderRadius: 1,
381
+ p: 1.5
382
+ },
383
+ children: [
384
+ /*#__PURE__*/ _jsxs(Stack, {
385
+ direction: "row",
386
+ spacing: 1,
387
+ sx: {
388
+ alignItems: 'center'
389
+ },
390
+ children: [
391
+ /*#__PURE__*/ _jsx(Typography, {
392
+ variant: "body2",
393
+ sx: {
394
+ flex: 1
395
+ },
396
+ noWrap: true,
397
+ children: installationHref(install.$id) ? /*#__PURE__*/ _jsx(AppLink, {
398
+ href: installationHref(install.$id),
399
+ color: "inherit",
400
+ underline: "hover",
401
+ children: (_ref1 = (_install_displayName = install.displayName) != null ? _install_displayName : install.pluginId) != null ? _ref1 : install.$id
402
+ }) : (_ref2 = (_install_displayName1 = install.displayName) != null ? _install_displayName1 : install.pluginId) != null ? _ref2 : install.$id
403
+ }),
404
+ /*#__PURE__*/ _jsx(Chip, {
405
+ size: "small",
406
+ label: `v${install.version}`
407
+ }),
408
+ revoked ? /*#__PURE__*/ _jsx(Chip, {
409
+ size: "small",
410
+ color: "error",
411
+ label: "disabled"
412
+ }) : null,
413
+ canUpgrade ? /*#__PURE__*/ _jsx(Button, {
414
+ size: "small",
415
+ disabled: busy === install.$id,
416
+ onClick: handleUpgrade(install),
417
+ children: `Upgrade to v${latest}`
418
+ }) : null,
419
+ orgId && !orgInstalls.some((entry)=>entry.$id === install.$id) ? /*#__PURE__*/ _jsx(Tooltip, {
420
+ title: "Install for every site in the organization and remove this site's own pin",
421
+ children: /*#__PURE__*/ _jsx(Button, {
422
+ size: "small",
423
+ disabled: busy === install.$id,
424
+ onClick: handleShareWithOrg(install),
425
+ children: 'Share with org'
426
+ })
427
+ }) : null,
428
+ /*#__PURE__*/ _jsx(Button, {
429
+ size: "small",
430
+ color: "error",
431
+ onClick: handleUninstall(install),
432
+ children: 'Uninstall'
433
+ })
434
+ ]
435
+ }),
436
+ /*#__PURE__*/ _jsx(Typography, {
437
+ variant: "caption",
438
+ color: "text.secondary",
439
+ noWrap: true,
440
+ children: `id: ${install.$id}`
441
+ }),
442
+ (((_capabilities_network = capabilities.network) == null ? void 0 : _capabilities_network.length) || ((_capabilities_events = capabilities.events) == null ? void 0 : _capabilities_events.length)) && /*#__PURE__*/ _jsx(Tooltip, {
443
+ title: "Declared in the plugin manifest, enforced by the sandbox",
444
+ children: /*#__PURE__*/ _jsx(Typography, {
445
+ variant: "caption",
446
+ color: "text.secondary",
447
+ children: [
448
+ ((_capabilities_network1 = capabilities.network) == null ? void 0 : _capabilities_network1.length) ? `network: ${capabilities.network.join(', ')}` : null,
449
+ ((_capabilities_events1 = capabilities.events) == null ? void 0 : _capabilities_events1.length) ? `events: ${capabilities.events.join(', ')}` : null
450
+ ].filter(Boolean).join(' · ')
451
+ })
452
+ }),
453
+ revoked ? /*#__PURE__*/ _jsxs(Alert, {
454
+ severity: "error",
455
+ sx: {
456
+ mt: 0.5
457
+ },
458
+ children: [
459
+ 'The platform disabled this plugin version. It renders ' + 'a placeholder on your site until you upgrade or ' + 'uninstall it.',
460
+ ((_revocationDetailByListing_install_$id = revocationDetailByListing[install.$id]) == null ? void 0 : _revocationDetailByListing_install_$id.reason) ? /*#__PURE__*/ _jsx(Typography, {
461
+ variant: "body2",
462
+ sx: {
463
+ mt: 1
464
+ },
465
+ children: `Reason: ${(_revocationDetailByListing_install_$id1 = revocationDetailByListing[install.$id]) == null ? void 0 : _revocationDetailByListing_install_$id1.reason}`
466
+ }) : null,
467
+ ((_revocationDetailByListing_install_$id2 = revocationDetailByListing[install.$id]) == null ? void 0 : _revocationDetailByListing_install_$id2.atMs) ? /*#__PURE__*/ _jsx(Typography, {
468
+ variant: "caption",
469
+ sx: {
470
+ display: 'block',
471
+ mt: 0.5
472
+ },
473
+ children: `Disabled ${new Date((_revocationDetailByListing_install_$id3 = revocationDetailByListing[install.$id]) == null ? void 0 : _revocationDetailByListing_install_$id3.atMs).toLocaleDateString()}`
474
+ }) : null
475
+ ]
476
+ }) : null
477
+ ]
478
+ }, install.$id);
479
+ }),
480
+ orgInstalls.map((install)=>{
481
+ var _compareArtifactVersions, _ref, _install_displayName, _ref1, _install_displayName1;
482
+ const latest = latestByListing[install.$id];
483
+ const canUpgrade = ((_compareArtifactVersions = compareArtifactVersions(install.version, latest)) != null ? _compareArtifactVersions : 0) < 0;
484
+ const shadowed = installs.some((entry)=>entry.$id === install.$id);
485
+ return /*#__PURE__*/ _jsxs(Stack, {
486
+ spacing: 0.5,
487
+ sx: {
488
+ border: '1px solid',
489
+ borderColor: 'divider',
490
+ borderRadius: 1,
491
+ p: 1.5
492
+ },
493
+ children: [
494
+ /*#__PURE__*/ _jsxs(Stack, {
495
+ direction: "row",
496
+ spacing: 1,
497
+ sx: {
498
+ alignItems: 'center'
499
+ },
500
+ children: [
501
+ /*#__PURE__*/ _jsx(Typography, {
502
+ variant: "body2",
503
+ sx: {
504
+ flex: 1
505
+ },
506
+ noWrap: true,
507
+ children: installationHref(install.$id) ? /*#__PURE__*/ _jsx(AppLink, {
508
+ href: installationHref(install.$id),
509
+ color: "inherit",
510
+ underline: "hover",
511
+ children: (_ref = (_install_displayName = install.displayName) != null ? _install_displayName : install.pluginId) != null ? _ref : install.$id
512
+ }) : (_ref1 = (_install_displayName1 = install.displayName) != null ? _install_displayName1 : install.pluginId) != null ? _ref1 : install.$id
513
+ }),
514
+ /*#__PURE__*/ _jsx(Chip, {
515
+ size: "small",
516
+ color: "primary",
517
+ label: "Organization"
518
+ }),
519
+ /*#__PURE__*/ _jsx(Chip, {
520
+ size: "small",
521
+ label: `v${install.version}`
522
+ }),
523
+ shadowed ? /*#__PURE__*/ _jsx(Tooltip, {
524
+ title: "This site has its own pin, which takes precedence here",
525
+ children: /*#__PURE__*/ _jsx(Chip, {
526
+ size: "small",
527
+ variant: "outlined",
528
+ label: "shadowed"
529
+ })
530
+ }) : null,
531
+ canUpgrade ? /*#__PURE__*/ _jsx(Button, {
532
+ size: "small",
533
+ disabled: busy === install.$id,
534
+ onClick: handleOrgUpgrade(install),
535
+ children: `Upgrade to v${latest}`
536
+ }) : null,
537
+ /*#__PURE__*/ _jsx(Button, {
538
+ size: "small",
539
+ color: "error",
540
+ onClick: handleOrgUninstall(install),
541
+ children: 'Uninstall'
542
+ })
543
+ ]
544
+ }),
545
+ /*#__PURE__*/ _jsx(Typography, {
546
+ variant: "caption",
547
+ color: "text.secondary",
548
+ noWrap: true,
549
+ children: `id: ${install.$id} · shared with every site in the org`
550
+ })
551
+ ]
552
+ }, `org-${install.$id}`);
553
+ }),
554
+ /*#__PURE__*/ _jsx(Typography, {
555
+ variant: "caption",
556
+ color: "text.secondary",
557
+ children: `Place a plugin on a screen with the Plugin element (component id ` + `"${PLUGIN_COMPONENT_ID}"), set to the listing id above.`
558
+ })
559
+ ]
560
+ })
561
+ });
562
+ }
563
+ HostPluginsCard.displayName = 'HostPluginsCard';
564
+ export default HostPluginsCard;
565
+
566
+ //# sourceMappingURL=host-plugins-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/host-plugins-card.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 buildRoute,\n PLUGIN_COMPONENT_ID,\n pluginDocsHelp,\n Route,\n} from '@aglyn/aglyn'\nimport {\n AppLink,\n CardDisplay,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Alert, Button, Chip, Stack, Tooltip, Typography } from '@mui/material'\nimport {\n collection,\n deleteDoc,\n doc,\n documentId,\n limit,\n query,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n compareArtifactVersions,\n isPluginRevoked,\n lockdownRefusalText,\n offeredPluginVersion,\n parseLockdownRefusal,\n} from '@aglyn/aglyn'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostOrgId,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\n\nexport interface HostPluginsCardProps {\n hostId: string\n /**\n * Org slug from the URL, when this card is rendered at org scope. With it,\n * each row links through to that installation's own page (AGL-1007);\n * without it the rows stay plain text rather than linking to nowhere.\n */\n orgSlug?: string\n}\n\n/**\n * Installed marketplace plugins (AGL-45): lists the host's pinned plugin\n * installs with their capabilities, flags available upgrades (latest\n * listing version ≠ pinned) and platform kill switches (public\n * `revocations` read), and offers explicit upgrade/uninstall. Upgrades go\n * through `/api/marketplace/install-plugin` so the new pin is validated\n * server-side; uninstall removes the host install doc. Place the installed\n * plugin on a screen with the Plugin element (listing id).\n */\nexport function HostPluginsCard(props: HostPluginsCardProps) {\n const { hostId, orgSlug } = props\n // One row → one installation page (AGL-1007). The name is the link, so a\n // row stays clickable without swallowing its own action buttons.\n const installationHref = (listingId: string) =>\n orgSlug\n ? buildRoute(Route.ORG_PLUGIN_INSTALLATION, {\n orgSlug,\n pluginRef: listingId,\n })\n : undefined\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const [busy, setBusy] = useState<string | null>(null)\n\n const orgId = useHostOrgId(hostId)\n const { data: installDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'installs'), limit(50)),\n [firestore, hostId],\n { idField: '$id' },\n )\n // Org-tier pins (AGL-237): apply to every host in the org; a host pin\n // of the same listing shadows the org one. Held at null while\n // `useHostOrgId` is in flight, never `orgs/-pending-` (AGL-1440):\n // installs are member-gated, so the sentinel was a guaranteed-denied\n // listen on every mount of this card.\n const { data: orgInstallDocs } = useFirestoreCollection<any>(\n () =>\n orgId\n ? query(collection(firestore, 'orgs', orgId, 'installs'), limit(50))\n : null,\n [firestore, orgId],\n { idField: '$id' },\n )\n const orgInstalls = useMemo(\n () => [...((orgInstallDocs as any[]) ?? [])],\n [orgInstallDocs],\n )\n const installs = useMemo(\n () => [...((installDocs as any[]) ?? [])],\n [installDocs],\n )\n const listingIds = useMemo(\n () =>\n [\n ...new Set([\n ...installs.map((install) => install.$id),\n ...orgInstalls.map((install) => install.$id),\n ]),\n ].slice(0, 10),\n [installs, orgInstalls],\n )\n\n // Latest published version per listing (upgrade detection) — public read.\n const { data: listingDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'marketplaceListings'),\n where(documentId(), 'in', listingIds.length ? listingIds : ['-none-']),\n ),\n [firestore, listingIds.join(',')],\n { idField: '$id' },\n )\n // Kill switches (public revocations read) for the installed listings.\n const { data: revocationDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'revocations'),\n where(documentId(), 'in', listingIds.length ? listingIds : ['-none-']),\n ),\n [firestore, listingIds.join(',')],\n { idField: '$id' },\n )\n const revokedByListing = useMemo(() => {\n const map: Record<string, boolean> = {}\n for (const install of installs) {\n const revocation = ((revocationDocs as any[]) ?? []).find(\n (doc) => doc.$id === install.$id,\n )\n if (!revocation) continue\n // THE SHARED PREDICATE, not a fourth copy of it (AGL-2305). This card\n // carried a byte-for-byte duplicate of `isPluginRevoked`'s body, which\n // is precisely what AGL-1085 collapsed three inline copies into one to\n // stop: a reader that disagrees with the writer about this document's\n // shape is how a kill switch silently stops killing. It happened to be\n // correct; being correct today is not the property that matters.\n map[install.$id] = isPluginRevoked(revocation, install.version)\n }\n return map\n }, [installs, revocationDocs])\n\n /*==========================================\n * WHY IT WAS DISABLED (AGL-2328).\n *\n * Staff are REQUIRED to type a reason to revoke a plugin version — the\n * route refuses without one — and until now the customer whose site the\n * plugin stopped working on was shown a bare \"disabled\" chip and a generic\n * paragraph. The reason was stored, in the same document this card already\n * reads, one field away from the flag it renders. Every consumer of\n * `revocations` reads `versions` and nothing else; the type's own comment\n * calls `versions` \"the ONLY field any reader consults\", which was true and\n * is the defect.\n *\n * Only the REASON and the DATE are surfaced. `revokedBy` is a staff uid and\n * belongs in the audit log, not on a customer's screen.\n *=========================================*/\n const revocationDetailByListing = useMemo(() => {\n const map: Record<string, { reason: string | null; atMs: number | null }> =\n {}\n for (const doc of ((revocationDocs as any[]) ?? [])) {\n const at = doc.revokedAt\n map[doc.$id] = {\n reason:\n typeof doc.reason === 'string' && doc.reason.trim()\n ? doc.reason.trim()\n : null,\n atMs:\n at?.toMillis?.() ?? (typeof at?.seconds === 'number' ? at.seconds * 1000 : null),\n }\n }\n return map\n }, [revocationDocs])\n\n // The newest INSTALLABLE version, not merely the newest approved one\n // (AGL-1016, corrected by AGL-2368).\n //\n // Offering `latestVersion` here put an Upgrade button in front of every\n // workspace the moment a publisher uploaded, and the install route then\n // refused the click — AGL-966 only ever hands out reviewed bytes. The\n // mirror fixed that and then reproduced it one state over: nothing cleared\n // it when a version was revoked, so the Upgrade button pointed at bytes the\n // kill switch had stopped. Every writer of the mirror now derives it from\n // `newestInstallableVersion`, and this card holds the revocation document\n // ALREADY — it is right there, feeding the disabled chip below — so it\n // cross-checks rather than trusting a cache written by a separate,\n // non-transactional write it can observe mid-flight.\n const latestByListing = useMemo(() => {\n const map: Record<string, string> = {}\n for (const listing of (listingDocs as any[]) ?? []) {\n const revocation = ((revocationDocs as any[]) ?? []).find(\n (doc) => doc.$id === listing.$id,\n )\n map[listing.$id] = offeredPluginVersion(listing, revocation) ?? ''\n }\n return map\n }, [listingDocs, revocationDocs])\n\n const handleUpgrade = useCallback(\n (install: any) => async () => {\n setBusy(install.$id)\n try {\n const response = await authorizedFetch(\n user,\n '/api/marketplace/install-plugin',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, listingId: install.$id }),\n },\n )\n const payload = await response.json().catch(() => ({}))\n if (response.ok) {\n enqueueSnackbar(`Upgraded to ${payload.version}`, {\n variant: 'success',\n persist: false,\n })\n } else {\n // An installs lockdown refuses the upgrade route too (AGL-1532).\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n } else {\n enqueueSnackbar(payload?.error ?? 'Upgrade failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }\n } finally {\n setBusy(null)\n }\n },\n [hostId, user, enqueueSnackbar],\n )\n\n const requestPluginApi = useCallback(\n async (body: Record<string, unknown>) => {\n const response = await authorizedFetch(\n user,\n '/api/marketplace/install-plugin',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, ...body }),\n },\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n // Every install-class action in this card funnels through here\n // (share, org upgrade, uninstall at both scopes) — so does the\n // pause notice (AGL-1532).\n const locked = parseLockdownRefusal(response.status, payload)\n if (locked) {\n enqueueSnackbar(lockdownRefusalText(locked), {\n variant: 'warning',\n persist: true,\n })\n return null\n }\n enqueueSnackbar(payload?.error ?? 'Plugin operation failed', {\n variant: 'error',\n allowDuplicate: true,\n })\n return null\n }\n return payload\n },\n [hostId, user, enqueueSnackbar],\n )\n\n // Promote a host pin to the org tier (AGL-237): org pin first, then the\n // host pin is removed — host pins shadow org ones in the loader.\n const handleShareWithOrg = useCallback(\n (install: any) => async () => {\n setBusy(install.$id)\n try {\n const payload = await requestPluginApi({\n listingId: install.$id,\n scope: 'org',\n })\n if (!payload) return\n await deleteDoc(\n doc(firestore, 'hosts', hostId, 'installs', install.$id),\n )\n enqueueSnackbar('Plugin now installed for the whole organization', {\n variant: 'success',\n persist: false,\n })\n } finally {\n setBusy(null)\n }\n },\n [requestPluginApi, firestore, hostId, enqueueSnackbar],\n )\n\n const handleOrgUpgrade = useCallback(\n (install: any) => async () => {\n setBusy(install.$id)\n try {\n const payload = await requestPluginApi({\n listingId: install.$id,\n scope: 'org',\n })\n if (payload) {\n enqueueSnackbar(`Upgraded to ${payload.version}`, {\n variant: 'success',\n persist: false,\n })\n }\n } finally {\n setBusy(null)\n }\n },\n [requestPluginApi, enqueueSnackbar],\n )\n\n const handleOrgUninstall = useCallback(\n (install: any) => async () => {\n const confirmed = await confirm({\n title: `Uninstall \"${install.displayName ?? install.$id}\" org-wide?`,\n description:\n 'Every site in the organization loses this plugin unless it has ' +\n 'its own host-level pin. Data the plugin created stays untouched.',\n confirmationText: 'Uninstall',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const payload = await requestPluginApi({\n listingId: install.$id,\n scope: 'org',\n action: 'uninstall',\n })\n if (payload) {\n enqueueSnackbar('Plugin uninstalled org-wide', {\n variant: 'success',\n persist: false,\n })\n }\n },\n [confirm, requestPluginApi, enqueueSnackbar],\n )\n\n const handleUninstall = useCallback(\n (install: any) => async () => {\n const confirmed = await confirm({\n title: `Uninstall \"${install.displayName ?? install.$id}\"?`,\n description:\n 'Plugin elements pointing at it will show a placeholder until ' +\n 'reinstalled. Data the plugin created stays untouched.',\n confirmationText: 'Uninstall',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n // Through the API (AGL-424) so the org enablement switchboard stays\n // in step with the removed pin.\n const payload = await requestPluginApi({\n listingId: install.$id,\n action: 'uninstall',\n })\n if (payload) {\n enqueueSnackbar('Plugin uninstalled', {\n variant: 'success',\n persist: false,\n })\n }\n },\n [confirm, requestPluginApi, enqueueSnackbar],\n )\n\n return (\n <CardDisplay\n header=\"Marketplace installs\"\n help={pluginDocsHelp('plugins', { anchor: '#install--upgrade' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n {/* First-party plugins used to be re-listed here for context; that\n moved out (AGL-802) now that the switchboard sits directly above\n this card in Marketplace › Installed. This card is only the\n marketplace install pins. */}\n {/* \"Nothing installed\" has to mean nothing at either scope. This\n asked only about HOST pins, so an org-wide install printed the\n empty-state sentence directly above the row it was denying\n (AGL-1011) — most visible at org scope, which is where installs\n usually land org-wide. */}\n {installs.length === 0 && orgInstalls.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No marketplace plugins installed. Install one from the ' +\n 'marketplace, then add a Plugin element to a screen and set ' +\n 'its listing id.'}\n </Typography>\n ) : (\n installs.map((install) => {\n const latest = latestByListing[install.$id]\n const canUpgrade =\n (compareArtifactVersions(install.version, latest) ?? 0) < 0\n const revoked = revokedByListing[install.$id]\n const capabilities = install.manifest?.capabilities ?? {}\n return (\n <Stack\n key={install.$id}\n spacing={0.5}\n sx={{\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 1.5,\n }}\n >\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"body2\" sx={{ flex: 1 }} noWrap>\n {installationHref(install.$id) ? (\n <AppLink\n href={installationHref(install.$id)}\n color=\"inherit\"\n underline=\"hover\"\n >\n {install.displayName ?? install.pluginId ?? install.$id}\n </AppLink>\n ) : (\n (install.displayName ?? install.pluginId ?? install.$id)\n )}\n </Typography>\n <Chip size=\"small\" label={`v${install.version}`} />\n {revoked ? (\n <Chip size=\"small\" color=\"error\" label=\"disabled\" />\n ) : null}\n {canUpgrade ? (\n <Button\n size=\"small\"\n disabled={busy === install.$id}\n onClick={handleUpgrade(install)}\n >\n {`Upgrade to v${latest}`}\n </Button>\n ) : null}\n {orgId &&\n !orgInstalls.some((entry) => entry.$id === install.$id) ? (\n <Tooltip title=\"Install for every site in the organization and remove this site's own pin\">\n <Button\n size=\"small\"\n disabled={busy === install.$id}\n onClick={handleShareWithOrg(install)}\n >\n {'Share with org'}\n </Button>\n </Tooltip>\n ) : null}\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleUninstall(install)}\n >\n {'Uninstall'}\n </Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`id: ${install.$id}`}\n </Typography>\n {(capabilities.network?.length ||\n capabilities.events?.length) && (\n <Tooltip title=\"Declared in the plugin manifest, enforced by the sandbox\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n capabilities.network?.length\n ? `network: ${capabilities.network.join(', ')}`\n : null,\n capabilities.events?.length\n ? `events: ${capabilities.events.join(', ')}`\n : null,\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n </Tooltip>\n )}\n {revoked ? (\n <Alert severity=\"error\" sx={{ mt: 0.5 }}>\n {'The platform disabled this plugin version. It renders ' +\n 'a placeholder on your site until you upgrade or ' +\n 'uninstall it.'}\n {/*\n The reason staff were required to type, shown to the\n person it happened to (AGL-2328). Rendered only when one\n was recorded — a revocation written before the reason\n was required says so, rather than showing an empty\n quotation that reads as \"no reason given\".\n */}\n {revocationDetailByListing[install.$id]?.reason ? (\n <Typography variant=\"body2\" sx={{ mt: 1 }}>\n {`Reason: ${revocationDetailByListing[install.$id]?.reason}`}\n </Typography>\n ) : null}\n {revocationDetailByListing[install.$id]?.atMs ? (\n <Typography variant=\"caption\" sx={{ display: 'block', mt: 0.5 }}>\n {`Disabled ${new Date(\n revocationDetailByListing[install.$id]\n ?.atMs as number,\n ).toLocaleDateString()}`}\n </Typography>\n ) : null}\n </Alert>\n ) : null}\n </Stack>\n )\n })\n )}\n {orgInstalls.map((install) => {\n const latest = latestByListing[install.$id]\n const canUpgrade =\n (compareArtifactVersions(install.version, latest) ?? 0) < 0\n const shadowed = installs.some((entry) => entry.$id === install.$id)\n return (\n <Stack\n key={`org-${install.$id}`}\n spacing={0.5}\n sx={{\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 1.5,\n }}\n >\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }} noWrap>\n {installationHref(install.$id) ? (\n <AppLink\n href={installationHref(install.$id)}\n color=\"inherit\"\n underline=\"hover\"\n >\n {install.displayName ?? install.pluginId ?? install.$id}\n </AppLink>\n ) : (\n (install.displayName ?? install.pluginId ?? install.$id)\n )}\n </Typography>\n <Chip size=\"small\" color=\"primary\" label=\"Organization\" />\n <Chip size=\"small\" label={`v${install.version}`} />\n {shadowed ? (\n <Tooltip title=\"This site has its own pin, which takes precedence here\">\n <Chip size=\"small\" variant=\"outlined\" label=\"shadowed\" />\n </Tooltip>\n ) : null}\n {canUpgrade ? (\n <Button\n size=\"small\"\n disabled={busy === install.$id}\n onClick={handleOrgUpgrade(install)}\n >\n {`Upgrade to v${latest}`}\n </Button>\n ) : null}\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleOrgUninstall(install)}\n >\n {'Uninstall'}\n </Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`id: ${install.$id} · shared with every site in the org`}\n </Typography>\n </Stack>\n )\n })}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Place a plugin on a screen with the Plugin element (component id ` +\n `\"${PLUGIN_COMPONENT_ID}\"), set to the listing id above.`}\n </Typography>\n </Stack>\n </CardDisplay>\n )\n}\nHostPluginsCard.displayName = 'HostPluginsCard'\n\nexport default HostPluginsCard\n"],"names":["buildRoute","PLUGIN_COMPONENT_ID","pluginDocsHelp","Route","AppLink","CardDisplay","useConfirmationContext","useSnackbar","Alert","Button","Chip","Stack","Tooltip","Typography","collection","deleteDoc","doc","documentId","limit","query","where","useCallback","useMemo","useState","compareArtifactVersions","isPluginRevoked","lockdownRefusalText","offeredPluginVersion","parseLockdownRefusal","useFirestore","useFirestoreCollection","useHostOrgId","useUser","authorizedFetch","HostPluginsCard","props","hostId","orgSlug","installationHref","listingId","ORG_PLUGIN_INSTALLATION","pluginRef","undefined","firestore","data","user","enqueueSnackbar","confirm","busy","setBusy","orgId","installDocs","idField","orgInstallDocs","orgInstalls","installs","listingIds","Set","map","install","$id","slice","listingDocs","length","join","revocationDocs","revokedByListing","revocation","find","version","revocationDetailByListing","at","revokedAt","reason","trim","atMs","toMillis","seconds","latestByListing","listing","handleUpgrade","response","method","headers","body","JSON","stringify","payload","json","catch","ok","variant","persist","locked","status","error","allowDuplicate","requestPluginApi","handleShareWithOrg","scope","handleOrgUpgrade","handleOrgUninstall","confirmed","title","displayName","description","confirmationText","confirmationButtonProps","color","then","action","handleUninstall","header","help","anchor","contentGutterX","contentGutterY","spacing","capabilities","latest","canUpgrade","revoked","manifest","sx","border","borderColor","borderRadius","p","direction","alignItems","flex","noWrap","href","underline","pluginId","size","label","disabled","onClick","some","entry","network","events","filter","Boolean","severity","mt","display","Date","toLocaleDateString","shadowed"],"mappings":"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"}