@aglyn/plugins-marketplace 1.0.0-beta.149 → 1.0.0-beta.151

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 (92) hide show
  1. package/package.json +15 -11
  2. package/src/lib/components/edit-listing-dialog.component.d.ts +20 -0
  3. package/src/lib/components/edit-listing-dialog.component.js +51 -0
  4. package/src/lib/components/edit-listing-dialog.component.js.map +1 -0
  5. package/src/lib/components/listing-detail-editor.component.d.ts +24 -0
  6. package/src/lib/components/listing-detail-editor.component.js +457 -0
  7. package/src/lib/components/listing-detail-editor.component.js.map +1 -0
  8. package/src/lib/components/listing-detail-page.component.d.ts +28 -0
  9. package/src/lib/components/listing-detail-page.component.js +151 -0
  10. package/src/lib/components/listing-detail-page.component.js.map +1 -0
  11. package/src/lib/components/listing-review-status.component.d.ts +67 -0
  12. package/src/lib/components/listing-review-status.component.js +301 -0
  13. package/src/lib/components/listing-review-status.component.js.map +1 -0
  14. package/src/lib/components/listing-verification-request.component.d.ts +40 -0
  15. package/src/lib/components/listing-verification-request.component.js +170 -0
  16. package/src/lib/components/listing-verification-request.component.js.map +1 -0
  17. package/src/lib/components/marketplace-hub.component.d.ts +43 -0
  18. package/src/lib/components/marketplace-hub.component.js +244 -0
  19. package/src/lib/components/marketplace-hub.component.js.map +1 -0
  20. package/src/lib/components/marketplace-reports-page.component.d.ts +23 -0
  21. package/src/lib/components/marketplace-reports-page.component.js +324 -0
  22. package/src/lib/components/marketplace-reports-page.component.js.map +1 -0
  23. package/src/lib/components/org-licences-panel.component.d.ts +73 -0
  24. package/src/lib/components/org-licences-panel.component.js +318 -0
  25. package/src/lib/components/org-licences-panel.component.js.map +1 -0
  26. package/src/lib/components/org-publish-panel.component.d.ts +45 -0
  27. package/src/lib/components/org-publish-panel.component.js +402 -0
  28. package/src/lib/components/org-publish-panel.component.js.map +1 -0
  29. package/src/lib/components/org-seller-panel.component.d.ts +28 -0
  30. package/src/lib/components/org-seller-panel.component.js +956 -0
  31. package/src/lib/components/org-seller-panel.component.js.map +1 -0
  32. package/src/lib/components/plugin-review-detail.component.d.ts +16 -0
  33. package/src/lib/components/plugin-review-detail.component.js +1438 -0
  34. package/src/lib/components/plugin-review-detail.component.js.map +1 -0
  35. package/src/lib/components/plugin-reviews-queue.component.d.ts +13 -0
  36. package/src/lib/components/plugin-reviews-queue.component.js +385 -0
  37. package/src/lib/components/plugin-reviews-queue.component.js.map +1 -0
  38. package/src/lib/components/plugin-reviews-surface.component.d.ts +19 -0
  39. package/src/lib/components/plugin-reviews-surface.component.js +46 -0
  40. package/src/lib/components/plugin-reviews-surface.component.js.map +1 -0
  41. package/src/lib/components/publish-plugin-form.component.d.ts +61 -0
  42. package/src/lib/components/publish-plugin-form.component.js +857 -0
  43. package/src/lib/components/publish-plugin-form.component.js.map +1 -0
  44. package/src/lib/components/publish-plugin-page.component.d.ts +29 -0
  45. package/src/lib/components/publish-plugin-page.component.js +92 -0
  46. package/src/lib/components/publish-plugin-page.component.js.map +1 -0
  47. package/src/lib/components/publisher-profile-page.component.d.ts +13 -0
  48. package/src/lib/components/publisher-profile-page.component.js +261 -0
  49. package/src/lib/components/publisher-profile-page.component.js.map +1 -0
  50. package/src/lib/constants/listing-media.d.ts +28 -0
  51. package/src/lib/constants/listing-media.js +28 -0
  52. package/src/lib/constants/listing-media.js.map +1 -0
  53. package/src/lib/model/listing-social-card.d.ts +94 -0
  54. package/src/lib/model/listing-social-card.js +177 -0
  55. package/src/lib/model/listing-social-card.js.map +1 -0
  56. package/src/lib/model/marketplace-paths.d.ts +54 -0
  57. package/src/lib/model/marketplace-paths.js +59 -0
  58. package/src/lib/model/marketplace-paths.js.map +1 -0
  59. package/src/lib/model/payout-readiness.d.ts +81 -0
  60. package/src/lib/model/payout-readiness.js +52 -0
  61. package/src/lib/model/payout-readiness.js.map +1 -0
  62. package/src/lib/model/plugin-rejection-categories.d.ts +66 -0
  63. package/src/lib/model/plugin-rejection-categories.js +124 -0
  64. package/src/lib/model/plugin-rejection-categories.js.map +1 -0
  65. package/src/lib/model/plugin-review-checklist.d.ts +62 -0
  66. package/src/lib/model/plugin-review-checklist.js +131 -0
  67. package/src/lib/model/plugin-review-checklist.js.map +1 -0
  68. package/src/lib/model/plugin-review-status.d.ts +104 -0
  69. package/src/lib/model/plugin-review-status.js +126 -0
  70. package/src/lib/model/plugin-review-status.js.map +1 -0
  71. package/src/lib/model/seller-ledger-totals.d.ts +100 -0
  72. package/src/lib/model/seller-ledger-totals.js +96 -0
  73. package/src/lib/model/seller-ledger-totals.js.map +1 -0
  74. package/src/lib/plugin.js +170 -40
  75. package/src/lib/plugin.js.map +1 -1
  76. package/src/lib/server/admin-reports.d.ts +18 -0
  77. package/src/lib/server/admin-reports.js +280 -0
  78. package/src/lib/server/admin-reports.js.map +1 -0
  79. package/src/lib/server/admin-reviews.d.ts +18 -0
  80. package/src/lib/server/admin-reviews.js +1341 -0
  81. package/src/lib/server/admin-reviews.js.map +1 -0
  82. package/src/lib/server/listing-social-card.server.d.ts +24 -0
  83. package/src/lib/server/listing-social-card.server.js +65 -0
  84. package/src/lib/server/listing-social-card.server.js.map +1 -0
  85. package/src/lib/server/publisher-review-email.d.ts +54 -0
  86. package/src/lib/server/publisher-review-email.js +85 -0
  87. package/src/lib/server/publisher-review-email.js.map +1 -0
  88. package/src/lib/server/revoke-cache-drop.d.ts +59 -0
  89. package/src/lib/server/revoke-cache-drop.js +74 -0
  90. package/src/lib/server/revoke-cache-drop.js.map +1 -0
  91. package/src/lib/server.js +47 -0
  92. package/src/lib/server.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/model/plugin-review-status.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * What each review status actually means for customers (AGL-966).\n *\n * The raw values are the wrong thing to put in front of a reviewer:\n * \"listed\" and \"verified\" sound like a soft ranking, when in fact **listed\n * is the consequential one** — `isListingBrowsable` turns true, so the\n * plugin becomes installable by every workspace. Verified adds a badge on\n * top of that and ships nothing new. Anyone reading the queue needs to know\n * which of the two put executable code in front of customers.\n */\nexport interface ReviewStatusMeaning {\n /** Human label for the chip. */\n label: string\n /** One line: what this state means for customers, not for us. */\n meaning: string\n /** Installable by any workspace in this state? */\n live: boolean\n color: 'default' | 'success' | 'warning' | 'error' | 'info'\n}\n\nexport const REVIEW_STATUS_MEANINGS: Record<string, ReviewStatusMeaning> = {\n submitted: {\n label: 'Submitted',\n meaning: 'Waiting for a reviewer. Not in the marketplace, not installable.',\n live: false,\n color: 'default',\n },\n in_review: {\n label: 'In review',\n meaning:\n 'Someone is looking at it. Not in the marketplace, not installable.',\n live: false,\n color: 'info',\n },\n listed: {\n label: 'Listed',\n meaning:\n 'LIVE — browsable in the marketplace and installable by every workspace. This is the state that puts the code in front of customers.',\n live: true,\n color: 'warning',\n },\n verified: {\n label: 'Verified',\n meaning:\n 'LIVE, and carries the verified badge on its listing page — our own claim that a human reviewed it. Installability is identical to listed.',\n live: true,\n color: 'success',\n },\n rejected: {\n label: 'Rejected',\n meaning:\n 'Turned down with a reason the publisher was notified of. Not in the marketplace, not installable.',\n live: false,\n color: 'error',\n },\n}\n\n/**\n * Does this takedown strip the Verified badge? (AGL-1121, decided 2026-08-03.)\n *\n * Verified is our claim that a human vouched for the PUBLISHER. A listing-wide\n * takedown is us saying the opposite, so the two cannot both stand.\n *\n * Lives here, beside the status meanings, because it is a statement about what\n * the statuses mean rather than request handling — and it is extracted from the\n * route so the policy is reachable from a test. The three conditions each rule\n * out a real case:\n *\n * - `hide` only. A restore must NOT re-grant; regranting is `verify`, which\n * re-checks the checklist server-side. Getting the badge back is meant to\n * cost a re-review.\n * - Listing target only. The same endpoint hides individual user REVIEWS\n * (`reviewUid`), which say nothing about the publisher.\n * - Already `verified` only, so a takedown never rewrites some other verdict —\n * demoting a `rejected` listing to `listed` would be a promotion.\n *\n * Per-version revocation deliberately does not qualify: that withdraws the\n * claim about THOSE BYTES, which the separate per-version \"Reviewed\" chip\n * already carries.\n */\nexport function shouldStripVerifiedOnTakedown(options: {\n action: string\n reviewStatus: string | undefined\n /** False when the target is an individual user review, not the listing. */\n isListingTarget: boolean\n}): boolean {\n return (\n options.action === 'hide' &&\n options.isListingTarget &&\n options.reviewStatus === 'verified'\n )\n}\n\n/** What a stripped listing becomes. Not `rejected` — see the note above. */\nexport const VERIFIED_STRIPPED_STATUS = 'listed'\n\n/**\n * What `latestVersionReviewState` becomes when the offered version is revoked\n * (AGL-1121).\n *\n * `revoked`, not `rejected`: it was not turned down in review, it was killed\n * afterwards, and the two should not blur in the audit trail. Both consumers —\n * the browse card's \"Reviewed\" chip and the listing page's caution alert — test\n * against `'approved'`, so any non-approved value behaves correctly; naming it\n * honestly costs nothing.\n *\n * This value belongs to the LISTING's summary field, never to a version's own\n * `reviewState` — see `ListingLatestVersionReviewState` in the marketplace\n * model for the distinction and for why the staff queue must keep keying on\n * the version. The version keeps the `approved` it earned; only the listing's\n * summary flips.\n */\nexport const REVOKED_VERSION_REVIEW_STATE = 'revoked'\n\n/**\n * Does revoking this version withdraw the \"Reviewed\" claim on the listing?\n *\n * Only when it is the version customers are actually being offered. Both\n * consumers describe `latestVersion`, so revoking an older version says nothing\n * about what is on offer and must not touch the chip.\n *\n * This exists because keeping the Verified badge through a per-version\n * revocation is only defensible if the BYTES claim withdraws instead. That did\n * not happen before AGL-1121: `latestVersionReviewState` was written solely by\n * approve/reject and on publish, so a version approved and later revoked kept\n * `'approved'` — and because a per-version revocation deliberately does not hide\n * the listing, the marketplace kept telling customers a human had read the exact\n * bytes we had just stopped from executing.\n */\nexport function revocationWithdrawsReviewedClaim(options: {\n revokedVersion: string\n latestVersion: string | undefined\n}): boolean {\n return (\n Boolean(options.revokedVersion) &&\n options.revokedVersion === options.latestVersion\n )\n}\n\nexport function reviewStatusMeaning(status: string): ReviewStatusMeaning {\n return (\n REVIEW_STATUS_MEANINGS[status] ?? {\n label: status || 'Unknown',\n meaning: 'Unrecognised review state.',\n live: false,\n color: 'default',\n }\n )\n}\n"],"names":["REVIEW_STATUS_MEANINGS","submitted","label","meaning","live","color","in_review","listed","verified","rejected","shouldStripVerifiedOnTakedown","options","action","isListingTarget","reviewStatus","VERIFIED_STRIPPED_STATUS","REVOKED_VERSION_REVIEW_STATE","revocationWithdrawsReviewedClaim","Boolean","revokedVersion","latestVersion","reviewStatusMeaning","status"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;CASC,GAWD,OAAO,MAAMA,yBAA8D;IACzEC,WAAW;QACTC,OAAO;QACPC,SAAS;QACTC,MAAM;QACNC,OAAO;IACT;IACAC,WAAW;QACTJ,OAAO;QACPC,SACE;QACFC,MAAM;QACNC,OAAO;IACT;IACAE,QAAQ;QACNL,OAAO;QACPC,SACE;QACFC,MAAM;QACNC,OAAO;IACT;IACAG,UAAU;QACRN,OAAO;QACPC,SACE;QACFC,MAAM;QACNC,OAAO;IACT;IACAI,UAAU;QACRP,OAAO;QACPC,SACE;QACFC,MAAM;QACNC,OAAO;IACT;AACF,EAAC;AAED;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASK,8BAA8BC,OAK7C;IACC,OACEA,QAAQC,MAAM,KAAK,UACnBD,QAAQE,eAAe,IACvBF,QAAQG,YAAY,KAAK;AAE7B;AAEA,0EAA0E,GAC1E,OAAO,MAAMC,2BAA2B,SAAQ;AAEhD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,+BAA+B,UAAS;AAErD;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,iCAAiCN,OAGhD;IACC,OACEO,QAAQP,QAAQQ,cAAc,KAC9BR,QAAQQ,cAAc,KAAKR,QAAQS,aAAa;AAEpD;AAEA,OAAO,SAASC,oBAAoBC,MAAc;QAE9CtB;IADF,QACEA,iCAAAA,sBAAsB,CAACsB,OAAO,YAA9BtB,iCAAkC;QAChCE,OAAOoB,UAAU;QACjBnB,SAAS;QACTC,MAAM;QACNC,OAAO;IACT;AAEJ"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * WHAT THE PUBLISHER WAS ACTUALLY PAID (AGL-2158).
19
+ *
20
+ * The seller panel's Sales card summed `amountCents` and `feeCents` over EVERY
21
+ * sale and rendered `net = gross − fee`. That was wrong twice over.
22
+ *
23
+ * WRONG NUMBER. `amountCents` is the TAX-INCLUSIVE gross the buyer paid, while
24
+ * `feeCents` is computed off the PRE-TAX price — AGL-1544 pays the seller a
25
+ * fixed `payment_intent_data[transfer_data][amount]` rather than an
26
+ * application fee precisely so the sales tax stays with the platform that owes
27
+ * it. So `gross − fee` is `pretax + tax − fee`: the publisher's real payout
28
+ * PLUS tax that was never theirs. On the worked example ($100 listing, 20%
29
+ * rate, $8.25 tax) the card showed $88.25 against a transfer of $80.00.
30
+ * `transferCents` — the exact amount Stripe moved to their Connect account —
31
+ * was already on the purchase document and unused by this panel.
32
+ *
33
+ * WRONG SET. No refund or reversal filter, so a refunded sale and a lost
34
+ * chargeback both still counted as earnings.
35
+ *
36
+ * NETTED, NOT MERELY FILTERED. A refunded sale leaves the payout total and
37
+ * gets its own line. Dropping it silently would leave a publisher unable to
38
+ * reconcile a total that shrank between two page loads — the same complaint in
39
+ * a new shape.
40
+ *
41
+ * Extracted from the component so the arithmetic is testable without a render:
42
+ * every number here is money, and the defect was arithmetic, not layout.
43
+ */
44
+ export interface SellerLedgerSale {
45
+ /** Tax-INCLUSIVE gross the buyer paid. */
46
+ amountCents?: number;
47
+ /** Platform fee, computed off the PRE-TAX price. */
48
+ feeCents?: number;
49
+ /** Sales tax, collected under Aglyn's marketplace-provider registration. */
50
+ taxCents?: number;
51
+ /** What Stripe actually transferred to the publisher's Connect account. */
52
+ transferCents?: number;
53
+ /** Stamped by a full refund or a lost dispute (AGL-1546/1554). */
54
+ refundedAt?: unknown;
55
+ /** What the transfer reversal actually pulled back (AGL-1554/1995/2140). */
56
+ reversedTransferCents?: number;
57
+ /**
58
+ * What PARTIAL refunds have pulled back so far (AGL-2299).
59
+ *
60
+ * A separate field because it accumulates: there can be several partial
61
+ * refunds on one sale, while `reversedTransferCents` is the one-shot settle
62
+ * marker for a full refund or a lost dispute. The two never both apply to
63
+ * the same cents — the one-shot path caps itself at what the transfer has
64
+ * LEFT — so the publisher's real payout is the transfer minus both.
65
+ */
66
+ partialReversedTransferCents?: number;
67
+ }
68
+ export interface SellerLedgerTotals {
69
+ /** Sales still standing. */
70
+ paidCount: number;
71
+ /** Refunded or charged back. */
72
+ refundedCount: number;
73
+ /**
74
+ * What Stripe was ASKED to move to the publisher's Connect account, net of
75
+ * any pull-back — not what reached their bank.
76
+ *
77
+ * Named for the question it can actually answer. It is summed from
78
+ * `transferCents`, which is the instruction given at charge time; a payout
79
+ * that later fails on the way from the Connect balance to the bank leaves
80
+ * every figure here untouched. Calling it "net paid" made this number assert
81
+ * an arrival it has no knowledge of, and a publisher reading it during a
82
+ * failed payout was told their money had landed.
83
+ *
84
+ * Whether it LANDED is a separate fact, carried by
85
+ * `connectPayoutFailures` and mirrored onto the publisher profile, and the
86
+ * panel states it beside this figure rather than folding it in — an
87
+ * account-level payout failure cannot be attributed to any one sale, so
88
+ * netting it into a per-sale sum would invent a split that does not exist.
89
+ */
90
+ sentToStripeCents: number;
91
+ /** Tax-inclusive gross on the sales still standing. */
92
+ buyersPaidCents: number;
93
+ /** Tax on those sales — Aglyn's remittance liability, never the seller's. */
94
+ salesTaxCents: number;
95
+ /** Platform fee on those sales. */
96
+ platformFeeCents: number;
97
+ /** Pulled back out of the publisher's account on the refunded ones. */
98
+ returnedCents: number;
99
+ }
100
+ export declare function summarizeSellerLedger(sales: readonly SellerLedgerSale[] | null | undefined): SellerLedgerTotals;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * WHAT THE PUBLISHER WAS ACTUALLY PAID (AGL-2158).
18
+ *
19
+ * The seller panel's Sales card summed `amountCents` and `feeCents` over EVERY
20
+ * sale and rendered `net = gross − fee`. That was wrong twice over.
21
+ *
22
+ * WRONG NUMBER. `amountCents` is the TAX-INCLUSIVE gross the buyer paid, while
23
+ * `feeCents` is computed off the PRE-TAX price — AGL-1544 pays the seller a
24
+ * fixed `payment_intent_data[transfer_data][amount]` rather than an
25
+ * application fee precisely so the sales tax stays with the platform that owes
26
+ * it. So `gross − fee` is `pretax + tax − fee`: the publisher's real payout
27
+ * PLUS tax that was never theirs. On the worked example ($100 listing, 20%
28
+ * rate, $8.25 tax) the card showed $88.25 against a transfer of $80.00.
29
+ * `transferCents` — the exact amount Stripe moved to their Connect account —
30
+ * was already on the purchase document and unused by this panel.
31
+ *
32
+ * WRONG SET. No refund or reversal filter, so a refunded sale and a lost
33
+ * chargeback both still counted as earnings.
34
+ *
35
+ * NETTED, NOT MERELY FILTERED. A refunded sale leaves the payout total and
36
+ * gets its own line. Dropping it silently would leave a publisher unable to
37
+ * reconcile a total that shrank between two page loads — the same complaint in
38
+ * a new shape.
39
+ *
40
+ * Extracted from the component so the arithmetic is testable without a render:
41
+ * every number here is money, and the defect was arithmetic, not layout.
42
+ */ /**
43
+ * The amount Stripe moved.
44
+ *
45
+ * The fallback covers purchase documents written before AGL-1544 added
46
+ * `transferCents`, whose `amountCents` WAS the pre-tax price — so `amount −
47
+ * fee` was the transfer back then, and is the honest reading of those rows.
48
+ */ function transferOf(sale) {
49
+ var _sale_transferCents, _sale_amountCents, _sale_feeCents;
50
+ return Number((_sale_transferCents = sale.transferCents) != null ? _sale_transferCents : Number((_sale_amountCents = sale.amountCents) != null ? _sale_amountCents : 0) - Number((_sale_feeCents = sale.feeCents) != null ? _sale_feeCents : 0));
51
+ }
52
+ export function summarizeSellerLedger(sales) {
53
+ const all = sales != null ? sales : [];
54
+ const paid = all.filter((sale)=>!sale.refundedAt);
55
+ const refunded = all.filter((sale)=>Boolean(sale.refundedAt));
56
+ const sum = (rows, of)=>rows.reduce((total, sale)=>total + (Number(of(sale)) || 0), 0);
57
+ return {
58
+ paidCount: paid.length,
59
+ refundedCount: refunded.length,
60
+ // `reversedTransferCents` is SUBTRACTED rather than assumed to be the
61
+ // whole transfer: a partial pull-back leaves the publisher the remainder,
62
+ // and a reversal Stripe REFUSED (AGL-2140 records `reversalFailedAt` and
63
+ // the money stays with the publisher pending recovery) leaves them all of
64
+ // it. Summing the reversal that actually happened is true in every case.
65
+ //
66
+ // `partialReversedTransferCents` (AGL-2299) subtracts on the SAME rows,
67
+ // and it is the reason this line reads two fields rather than one: a
68
+ // partial refund takes the seller's proportional share back WITHOUT
69
+ // revoking, so the sale is still standing and still counts as paid. Left
70
+ // out, the panel would overstate the payout by exactly what came back.
71
+ sentToStripeCents: sum(paid, (sale)=>{
72
+ var _sale_reversedTransferCents, _sale_partialReversedTransferCents;
73
+ return transferOf(sale) - Number((_sale_reversedTransferCents = sale.reversedTransferCents) != null ? _sale_reversedTransferCents : 0) - Number((_sale_partialReversedTransferCents = sale.partialReversedTransferCents) != null ? _sale_partialReversedTransferCents : 0);
74
+ }),
75
+ buyersPaidCents: sum(paid, (sale)=>{
76
+ var _sale_amountCents;
77
+ return Number((_sale_amountCents = sale.amountCents) != null ? _sale_amountCents : 0);
78
+ }),
79
+ salesTaxCents: sum(paid, (sale)=>{
80
+ var _sale_taxCents;
81
+ return Number((_sale_taxCents = sale.taxCents) != null ? _sale_taxCents : 0);
82
+ }),
83
+ platformFeeCents: sum(paid, (sale)=>{
84
+ var _sale_feeCents;
85
+ return Number((_sale_feeCents = sale.feeCents) != null ? _sale_feeCents : 0);
86
+ }),
87
+ // What came back out of the PUBLISHER's account — not what the buyer got
88
+ // back, which also contains Aglyn's fee and Aglyn's tax.
89
+ returnedCents: sum(refunded, (sale)=>{
90
+ var _sale_reversedTransferCents, _sale_partialReversedTransferCents;
91
+ return Number((_sale_reversedTransferCents = sale.reversedTransferCents) != null ? _sale_reversedTransferCents : 0) + Number((_sale_partialReversedTransferCents = sale.partialReversedTransferCents) != null ? _sale_partialReversedTransferCents : 0);
92
+ })
93
+ };
94
+ }
95
+
96
+ //# sourceMappingURL=seller-ledger-totals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/model/seller-ledger-totals.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * WHAT THE PUBLISHER WAS ACTUALLY PAID (AGL-2158).\n *\n * The seller panel's Sales card summed `amountCents` and `feeCents` over EVERY\n * sale and rendered `net = gross − fee`. That was wrong twice over.\n *\n * WRONG NUMBER. `amountCents` is the TAX-INCLUSIVE gross the buyer paid, while\n * `feeCents` is computed off the PRE-TAX price — AGL-1544 pays the seller a\n * fixed `payment_intent_data[transfer_data][amount]` rather than an\n * application fee precisely so the sales tax stays with the platform that owes\n * it. So `gross − fee` is `pretax + tax − fee`: the publisher's real payout\n * PLUS tax that was never theirs. On the worked example ($100 listing, 20%\n * rate, $8.25 tax) the card showed $88.25 against a transfer of $80.00.\n * `transferCents` — the exact amount Stripe moved to their Connect account —\n * was already on the purchase document and unused by this panel.\n *\n * WRONG SET. No refund or reversal filter, so a refunded sale and a lost\n * chargeback both still counted as earnings.\n *\n * NETTED, NOT MERELY FILTERED. A refunded sale leaves the payout total and\n * gets its own line. Dropping it silently would leave a publisher unable to\n * reconcile a total that shrank between two page loads — the same complaint in\n * a new shape.\n *\n * Extracted from the component so the arithmetic is testable without a render:\n * every number here is money, and the defect was arithmetic, not layout.\n */\n\nexport interface SellerLedgerSale {\n /** Tax-INCLUSIVE gross the buyer paid. */\n amountCents?: number\n /** Platform fee, computed off the PRE-TAX price. */\n feeCents?: number\n /** Sales tax, collected under Aglyn's marketplace-provider registration. */\n taxCents?: number\n /** What Stripe actually transferred to the publisher's Connect account. */\n transferCents?: number\n /** Stamped by a full refund or a lost dispute (AGL-1546/1554). */\n refundedAt?: unknown\n /** What the transfer reversal actually pulled back (AGL-1554/1995/2140). */\n reversedTransferCents?: number\n /**\n * What PARTIAL refunds have pulled back so far (AGL-2299).\n *\n * A separate field because it accumulates: there can be several partial\n * refunds on one sale, while `reversedTransferCents` is the one-shot settle\n * marker for a full refund or a lost dispute. The two never both apply to\n * the same cents — the one-shot path caps itself at what the transfer has\n * LEFT — so the publisher's real payout is the transfer minus both.\n */\n partialReversedTransferCents?: number\n}\n\nexport interface SellerLedgerTotals {\n /** Sales still standing. */\n paidCount: number\n /** Refunded or charged back. */\n refundedCount: number\n /**\n * What Stripe was ASKED to move to the publisher's Connect account, net of\n * any pull-back — not what reached their bank.\n *\n * Named for the question it can actually answer. It is summed from\n * `transferCents`, which is the instruction given at charge time; a payout\n * that later fails on the way from the Connect balance to the bank leaves\n * every figure here untouched. Calling it \"net paid\" made this number assert\n * an arrival it has no knowledge of, and a publisher reading it during a\n * failed payout was told their money had landed.\n *\n * Whether it LANDED is a separate fact, carried by\n * `connectPayoutFailures` and mirrored onto the publisher profile, and the\n * panel states it beside this figure rather than folding it in — an\n * account-level payout failure cannot be attributed to any one sale, so\n * netting it into a per-sale sum would invent a split that does not exist.\n */\n sentToStripeCents: number\n /** Tax-inclusive gross on the sales still standing. */\n buyersPaidCents: number\n /** Tax on those sales — Aglyn's remittance liability, never the seller's. */\n salesTaxCents: number\n /** Platform fee on those sales. */\n platformFeeCents: number\n /** Pulled back out of the publisher's account on the refunded ones. */\n returnedCents: number\n}\n\n/**\n * The amount Stripe moved.\n *\n * The fallback covers purchase documents written before AGL-1544 added\n * `transferCents`, whose `amountCents` WAS the pre-tax price — so `amount −\n * fee` was the transfer back then, and is the honest reading of those rows.\n */\nfunction transferOf(sale: SellerLedgerSale): number {\n return Number(\n sale.transferCents ??\n Number(sale.amountCents ?? 0) - Number(sale.feeCents ?? 0),\n )\n}\n\nexport function summarizeSellerLedger(\n sales: readonly SellerLedgerSale[] | null | undefined,\n): SellerLedgerTotals {\n const all = sales ?? []\n const paid = all.filter((sale) => !sale.refundedAt)\n const refunded = all.filter((sale) => Boolean(sale.refundedAt))\n const sum = (\n rows: readonly SellerLedgerSale[],\n of: (sale: SellerLedgerSale) => number,\n ) => rows.reduce((total, sale) => total + (Number(of(sale)) || 0), 0)\n return {\n paidCount: paid.length,\n refundedCount: refunded.length,\n // `reversedTransferCents` is SUBTRACTED rather than assumed to be the\n // whole transfer: a partial pull-back leaves the publisher the remainder,\n // and a reversal Stripe REFUSED (AGL-2140 records `reversalFailedAt` and\n // the money stays with the publisher pending recovery) leaves them all of\n // it. Summing the reversal that actually happened is true in every case.\n //\n // `partialReversedTransferCents` (AGL-2299) subtracts on the SAME rows,\n // and it is the reason this line reads two fields rather than one: a\n // partial refund takes the seller's proportional share back WITHOUT\n // revoking, so the sale is still standing and still counts as paid. Left\n // out, the panel would overstate the payout by exactly what came back.\n sentToStripeCents: sum(\n paid,\n (sale) =>\n transferOf(sale) -\n Number(sale.reversedTransferCents ?? 0) -\n Number(sale.partialReversedTransferCents ?? 0),\n ),\n buyersPaidCents: sum(paid, (sale) => Number(sale.amountCents ?? 0)),\n salesTaxCents: sum(paid, (sale) => Number(sale.taxCents ?? 0)),\n platformFeeCents: sum(paid, (sale) => Number(sale.feeCents ?? 0)),\n // What came back out of the PUBLISHER's account — not what the buyer got\n // back, which also contains Aglyn's fee and Aglyn's tax.\n returnedCents: sum(\n refunded,\n (sale) =>\n Number(sale.reversedTransferCents ?? 0) +\n Number(sale.partialReversedTransferCents ?? 0),\n ),\n }\n}\n"],"names":["transferOf","sale","Number","transferCents","amountCents","feeCents","summarizeSellerLedger","sales","all","paid","filter","refundedAt","refunded","Boolean","sum","rows","of","reduce","total","paidCount","length","refundedCount","sentToStripeCents","reversedTransferCents","partialReversedTransferCents","buyersPaidCents","salesTaxCents","taxCents","platformFeeCents","returnedCents"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GA4DD;;;;;;CAMC,GACD,SAASA,WAAWC,IAAsB;QAEtCA,qBACSA,mBAAgCA;IAF3C,OAAOC,QACLD,sBAAAA,KAAKE,aAAa,YAAlBF,sBACEC,QAAOD,oBAAAA,KAAKG,WAAW,YAAhBH,oBAAoB,KAAKC,QAAOD,iBAAAA,KAAKI,QAAQ,YAAbJ,iBAAiB;AAE9D;AAEA,OAAO,SAASK,sBACdC,KAAqD;IAErD,MAAMC,MAAMD,gBAAAA,QAAS,EAAE;IACvB,MAAME,OAAOD,IAAIE,MAAM,CAAC,CAACT,OAAS,CAACA,KAAKU,UAAU;IAClD,MAAMC,WAAWJ,IAAIE,MAAM,CAAC,CAACT,OAASY,QAAQZ,KAAKU,UAAU;IAC7D,MAAMG,MAAM,CACVC,MACAC,KACGD,KAAKE,MAAM,CAAC,CAACC,OAAOjB,OAASiB,QAAShB,CAAAA,OAAOc,GAAGf,UAAU,CAAA,GAAI;IACnE,OAAO;QACLkB,WAAWV,KAAKW,MAAM;QACtBC,eAAeT,SAASQ,MAAM;QAC9B,sEAAsE;QACtE,0EAA0E;QAC1E,yEAAyE;QACzE,0EAA0E;QAC1E,yEAAyE;QACzE,EAAE;QACF,wEAAwE;QACxE,qEAAqE;QACrE,oEAAoE;QACpE,yEAAyE;QACzE,uEAAuE;QACvEE,mBAAmBR,IACjBL,MACA,CAACR;gBAEQA,6BACAA;mBAFPD,WAAWC,QACXC,QAAOD,8BAAAA,KAAKsB,qBAAqB,YAA1BtB,8BAA8B,KACrCC,QAAOD,qCAAAA,KAAKuB,4BAA4B,YAAjCvB,qCAAqC;;QAEhDwB,iBAAiBX,IAAIL,MAAM,CAACR;gBAAgBA;mBAAPC,QAAOD,oBAAAA,KAAKG,WAAW,YAAhBH,oBAAoB;;QAChEyB,eAAeZ,IAAIL,MAAM,CAACR;gBAAgBA;mBAAPC,QAAOD,iBAAAA,KAAK0B,QAAQ,YAAb1B,iBAAiB;;QAC3D2B,kBAAkBd,IAAIL,MAAM,CAACR;gBAAgBA;mBAAPC,QAAOD,iBAAAA,KAAKI,QAAQ,YAAbJ,iBAAiB;;QAC9D,yEAAyE;QACzE,yDAAyD;QACzD4B,eAAef,IACbF,UACA,CAACX;gBACQA,6BACAA;mBADPC,QAAOD,8BAAAA,KAAKsB,qBAAqB,YAA1BtB,8BAA8B,KACrCC,QAAOD,qCAAAA,KAAKuB,4BAA4B,YAAjCvB,qCAAqC;;IAElD;AACF"}
package/src/lib/plugin.js CHANGED
@@ -15,12 +15,13 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */ import * as Aglyn from "@aglyn/aglyn";
18
- import MarketplaceBrowse from "./components/marketplace-browse.component.js";
19
- import MarketplacePaymentsNotice from "./components/marketplace-payments-notice.component.js";
20
- import HostPluginsCard from "./components/host-plugins-card.component.js";
18
+ import { ICON_VARIANT_SYMBOL_FLAG } from "@aglyn/shared-data-enums";
19
+ import { mdiStorefrontOutline } from "@aglyn/shared-data-mdi";
20
+ import MarketplaceHub from "./components/marketplace-hub.component.js";
21
+ import MarketplaceReportsPage from "./components/marketplace-reports-page.component.js";
22
+ import PluginReviewsSurface from "./components/plugin-reviews-surface.component.js";
21
23
  import PluginSiteSetPanel from "./components/plugin-site-set-panel.component.js";
22
24
  import PublishArtifactDialog from "./components/publish-artifact-dialog.component.js";
23
- import { MarketplaceListingContent } from "./components/listing-content.component.js";
24
25
  import { BUNDLE_ID } from "./constants/bundle-common.js";
25
26
  import { RATING_FIELD } from "./model/rating-field.js";
26
27
  import RatingInput from "./components/rating-input.component.js";
@@ -41,42 +42,15 @@ import RatingInput from "./components/rating-input.component.js";
41
42
  Input: RatingInput
42
43
  }));
43
44
  Aglyn.registerConsoleExtension({
44
- // Listing detail content (AGL-419): the app route keeps the chrome
45
- // and renders this through the 'marketplaceListing' slot.
46
- widgets: [
47
- {
48
- slot: 'marketplaceListing',
49
- widgetId: 'marketplace-listing-content',
50
- Component: MarketplaceListingContent
51
- },
52
- // What this deployment cannot do, said BEFORE the click (AGL-2019,
53
- // moved here by AGL-3080). The sentence names what still works
54
- // without a Stripe platform — browsing and free installs — which is
55
- // this plugin's knowledge; the app supplies only the fact, through
56
- // the deployment-capability context its org layout provides. The
57
- // widget draws nothing at all on a configured deployment.
58
- {
59
- slot: 'marketplaceCapability',
60
- widgetId: 'marketplace-payments-notice',
61
- Component: MarketplacePaymentsNotice
62
- },
63
- // Org marketplace browse (AGL-772): the org-scope `/marketplace`
64
- // page renders this with an acting hostId + orgScoped, so listing
65
- // links resolve to the org route. The single place to browse/install,
66
- // replacing the per-site marketplace tab.
67
- {
68
- slot: 'orgMarketplace',
69
- widgetId: 'marketplace-org-marketplace',
70
- Component: MarketplaceBrowse
71
- },
72
- // Installed add-ons management (AGL-423): the org "Plugins &
73
- // add-ons" hub renders this with an acting hostId — the card lists
74
- // host + org install pins with upgrade/uninstall/share-with-org.
75
- {
76
- slot: 'orgAddons',
77
- widgetId: 'marketplace-installed-addons',
78
- Component: HostPluginsCard
79
- },
45
+ /*
46
+ * Four widgets fewer since AGL-3080 — the listing body, the capability
47
+ * notice, browse, and installed add-ons. Their zones existed for one
48
+ * reason: a CONSOLE ROUTE had to show them and an app may not import a
49
+ * plugin. The hub is this plugin's own surface now, so those components
50
+ * are plain imports and the four zones are gone from the catalog.
51
+ *
52
+ * What is left is what a console page OTHER than the marketplace draws.
53
+ */ widgets: [
80
54
  // The site set for one installation (AGL-1007): the same control the
81
55
  // listing page uses, exposed so the installation detail page can show
82
56
  // it without the app importing this plugin.
@@ -96,6 +70,162 @@ import RatingInput from "./components/rating-input.component.js";
96
70
  Component: PublishArtifactDialog
97
71
  }
98
72
  ],
73
+ /**
74
+ * THE MARKETPLACE HUB, as a declaration (AGL-3080).
75
+ *
76
+ * Seventeen hand-written console routes until now — the eight sections
77
+ * below plus a listing, a publisher storefront and a publish form —
78
+ * whose whole job was assembling chrome around bodies that already
79
+ * belonged to this plugin. The shell's generic org plugin route does
80
+ * that assembly for every other surface from exactly this.
81
+ *
82
+ * `ownsSubtree` is what keeps every URL the same. A segment naming a
83
+ * section below resolves as that section; anything else beneath
84
+ * `/marketplace` is handed to the page as `segments`, which is how
85
+ * `/{org}/marketplace/{listingId}` still opens a listing. The cost is
86
+ * stated where the flag is declared: this surface can no longer tell a
87
+ * typo from an id, so it owns saying "no such thing" — which a listing
88
+ * page has to do anyway for one deleted while a link to it was still in
89
+ * someone's inbox.
90
+ */ orgNavItems: [
91
+ {
92
+ label: 'Marketplace',
93
+ href: '/marketplace',
94
+ navTabId: 'nav-tab-org-marketplace',
95
+ icon: {
96
+ path: mdiStorefrontOutline.path
97
+ },
98
+ ownsSubtree: true,
99
+ Component: MarketplaceHub,
100
+ header: {
101
+ title: 'Marketplace',
102
+ icon: {
103
+ path: mdiStorefrontOutline.path
104
+ },
105
+ docsTopic: 'plugins'
106
+ },
107
+ sections: [
108
+ // "Browse All" (AGL-1024): the same grid also renders
109
+ // publisher-filtered views, so the unqualified verb was ambiguous
110
+ // about which you were getting.
111
+ {
112
+ id: 'browse',
113
+ label: 'Browse All'
114
+ },
115
+ {
116
+ id: 'installed',
117
+ label: 'Installed'
118
+ },
119
+ /*
120
+ * What this workspace OWNS (AGL-2331) — an org can hold a licence
121
+ * nobody has installed, and a member can install something they
122
+ * never bought. Buyer-side, so deliberately NOT gated like the
123
+ * seller sections below: the person who needs it is often not a
124
+ * publisher at all.
125
+ *
126
+ * `purchase` lands here: Stripe bakes it into the checkout session
127
+ * and holds the URL, and a buyer coming back wants what they now
128
+ * own.
129
+ */ {
130
+ id: 'licences',
131
+ label: 'Licenses',
132
+ landsOnQuery: [
133
+ 'purchase'
134
+ ]
135
+ },
136
+ /*
137
+ * The seller half. Each reads the organization's REVENUE or its
138
+ * payout account, so each names the permission rather than relying
139
+ * on a hidden tab — a URL can be typed whether or not a tab was
140
+ * ever offered, and the shell applies this to the rail and to the
141
+ * deep link as one verdict.
142
+ */ {
143
+ id: 'upload',
144
+ // Covers uploading a bundle as well as publishing an existing
145
+ // artifact (AGL-1024).
146
+ label: 'Upload / Publish',
147
+ permission: 'publishToMarketplace'
148
+ },
149
+ {
150
+ id: 'profile',
151
+ // Whose profile (AGL-1024) — the console also has org and user
152
+ // profiles.
153
+ label: 'Publisher Profile',
154
+ permission: 'publishToMarketplace'
155
+ },
156
+ {
157
+ id: 'listings',
158
+ label: 'Listings',
159
+ permission: 'publishToMarketplace'
160
+ },
161
+ {
162
+ id: 'payouts',
163
+ label: 'Payouts',
164
+ permission: 'publishToMarketplace',
165
+ // Stripe Connect onboarding returns with this, from
166
+ // `server/connect.ts`. A seller coming back wants Payouts.
167
+ landsOnQuery: [
168
+ 'connect'
169
+ ]
170
+ },
171
+ {
172
+ id: 'sales',
173
+ label: 'Sales',
174
+ permission: 'publishToMarketplace'
175
+ }
176
+ ]
177
+ }
178
+ ],
179
+ /**
180
+ * The report queue, in the staff area (AGL-2310, moved by AGL-3080).
181
+ *
182
+ * `marketplaceReports` is a collection only this plugin writes, and the
183
+ * queue that triages it was a console staff route because the staff area
184
+ * had no way for a plugin to own a page. It does (AGL-2939), and the
185
+ * shell serves this at the same `/admin/marketplace-reports` it always
186
+ * had — a staff page's id IS its URL segment.
187
+ */ staffPages: [
188
+ {
189
+ id: 'marketplace-reports',
190
+ label: 'Marketplace reports',
191
+ header: {
192
+ title: 'Marketplace Reports',
193
+ icon: {
194
+ path: ICON_VARIANT_SYMBOL_FLAG.path
195
+ },
196
+ // The abuse queue's topic, for the reason the page's own help
197
+ // gives. The page publishes the `#statuses` anchor itself, which a
198
+ // `staffPages` entry cannot carry.
199
+ docsTopic: 'abuseReports'
200
+ },
201
+ Component: MarketplaceReportsPage
202
+ },
203
+ /**
204
+ * The review queue (AGL-432, moved by AGL-3080).
205
+ *
206
+ * `ownsSubtree` is what makes the move possible at all: the queue is a
207
+ * list and each row opens one submission at
208
+ * `/admin/plugin-reviews/{listingId}`, and a staff page without it
209
+ * could only ever BE the list. Same URLs as the console routes it
210
+ * replaces — a staff page's id IS its segment under `/admin`.
211
+ *
212
+ * The queue carries no signing authority. Granting realm trust is a
213
+ * separate super-only act on its own route; listing and verifying here
214
+ * never signs anything.
215
+ */ {
216
+ id: 'plugin-reviews',
217
+ label: 'Plugin reviews',
218
+ ownsSubtree: true,
219
+ header: {
220
+ title: 'Plugin reviews',
221
+ icon: {
222
+ path: ICON_VARIANT_SYMBOL_FLAG.path
223
+ },
224
+ docsTopic: 'staffConsole'
225
+ },
226
+ Component: PluginReviewsSurface
227
+ }
228
+ ],
99
229
  pluginId: BUNDLE_ID,
100
230
  displayName: 'Marketplace'
101
231
  });
@@ -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 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"}
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 { ICON_VARIANT_SYMBOL_FLAG } from '@aglyn/shared-data-enums'\nimport { mdiStorefrontOutline } from '@aglyn/shared-data-mdi'\nimport MarketplaceBrowse from './components/marketplace-browse.component'\nimport MarketplaceHub from './components/marketplace-hub.component'\nimport MarketplaceReportsPage from './components/marketplace-reports-page.component'\nimport PluginReviewsSurface from './components/plugin-reviews-surface.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 /*\n * Four widgets fewer since AGL-3080 — the listing body, the capability\n * notice, browse, and installed add-ons. Their zones existed for one\n * reason: a CONSOLE ROUTE had to show them and an app may not import a\n * plugin. The hub is this plugin's own surface now, so those components\n * are plain imports and the four zones are gone from the catalog.\n *\n * What is left is what a console page OTHER than the marketplace draws.\n */\n widgets: [\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 /**\n * THE MARKETPLACE HUB, as a declaration (AGL-3080).\n *\n * Seventeen hand-written console routes until now — the eight sections\n * below plus a listing, a publisher storefront and a publish form —\n * whose whole job was assembling chrome around bodies that already\n * belonged to this plugin. The shell's generic org plugin route does\n * that assembly for every other surface from exactly this.\n *\n * `ownsSubtree` is what keeps every URL the same. A segment naming a\n * section below resolves as that section; anything else beneath\n * `/marketplace` is handed to the page as `segments`, which is how\n * `/{org}/marketplace/{listingId}` still opens a listing. The cost is\n * stated where the flag is declared: this surface can no longer tell a\n * typo from an id, so it owns saying \"no such thing\" — which a listing\n * page has to do anyway for one deleted while a link to it was still in\n * someone's inbox.\n */\n orgNavItems: [\n {\n label: 'Marketplace',\n href: '/marketplace',\n navTabId: 'nav-tab-org-marketplace',\n icon: { path: mdiStorefrontOutline.path },\n ownsSubtree: true,\n Component: MarketplaceHub,\n header: {\n title: 'Marketplace',\n icon: { path: mdiStorefrontOutline.path },\n docsTopic: 'plugins',\n },\n sections: [\n // \"Browse All\" (AGL-1024): the same grid also renders\n // publisher-filtered views, so the unqualified verb was ambiguous\n // about which you were getting.\n { id: 'browse', label: 'Browse All' },\n { id: 'installed', label: 'Installed' },\n /*\n * What this workspace OWNS (AGL-2331) — an org can hold a licence\n * nobody has installed, and a member can install something they\n * never bought. Buyer-side, so deliberately NOT gated like the\n * seller sections below: the person who needs it is often not a\n * publisher at all.\n *\n * `purchase` lands here: Stripe bakes it into the checkout session\n * and holds the URL, and a buyer coming back wants what they now\n * own.\n */\n {\n id: 'licences',\n label: 'Licenses',\n landsOnQuery: ['purchase'],\n },\n /*\n * The seller half. Each reads the organization's REVENUE or its\n * payout account, so each names the permission rather than relying\n * on a hidden tab — a URL can be typed whether or not a tab was\n * ever offered, and the shell applies this to the rail and to the\n * deep link as one verdict.\n */\n {\n id: 'upload',\n // Covers uploading a bundle as well as publishing an existing\n // artifact (AGL-1024).\n label: 'Upload / Publish',\n permission: 'publishToMarketplace',\n },\n {\n id: 'profile',\n // Whose profile (AGL-1024) — the console also has org and user\n // profiles.\n label: 'Publisher Profile',\n permission: 'publishToMarketplace',\n },\n {\n id: 'listings',\n label: 'Listings',\n permission: 'publishToMarketplace',\n },\n {\n id: 'payouts',\n label: 'Payouts',\n permission: 'publishToMarketplace',\n // Stripe Connect onboarding returns with this, from\n // `server/connect.ts`. A seller coming back wants Payouts.\n landsOnQuery: ['connect'],\n },\n {\n id: 'sales',\n label: 'Sales',\n permission: 'publishToMarketplace',\n },\n ],\n },\n ],\n /**\n * The report queue, in the staff area (AGL-2310, moved by AGL-3080).\n *\n * `marketplaceReports` is a collection only this plugin writes, and the\n * queue that triages it was a console staff route because the staff area\n * had no way for a plugin to own a page. It does (AGL-2939), and the\n * shell serves this at the same `/admin/marketplace-reports` it always\n * had — a staff page's id IS its URL segment.\n */\n staffPages: [\n {\n id: 'marketplace-reports',\n label: 'Marketplace reports',\n header: {\n title: 'Marketplace Reports',\n icon: { path: ICON_VARIANT_SYMBOL_FLAG.path },\n // The abuse queue's topic, for the reason the page's own help\n // gives. The page publishes the `#statuses` anchor itself, which a\n // `staffPages` entry cannot carry.\n docsTopic: 'abuseReports',\n },\n Component: MarketplaceReportsPage,\n },\n /**\n * The review queue (AGL-432, moved by AGL-3080).\n *\n * `ownsSubtree` is what makes the move possible at all: the queue is a\n * list and each row opens one submission at\n * `/admin/plugin-reviews/{listingId}`, and a staff page without it\n * could only ever BE the list. Same URLs as the console routes it\n * replaces — a staff page's id IS its segment under `/admin`.\n *\n * The queue carries no signing authority. Granting realm trust is a\n * separate super-only act on its own route; listing and verifying here\n * never signs anything.\n */\n {\n id: 'plugin-reviews',\n label: 'Plugin reviews',\n ownsSubtree: true,\n header: {\n title: 'Plugin reviews',\n icon: { path: ICON_VARIANT_SYMBOL_FLAG.path },\n docsTopic: 'staffConsole',\n },\n Component: PluginReviewsSurface,\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","ICON_VARIANT_SYMBOL_FLAG","mdiStorefrontOutline","MarketplaceHub","MarketplaceReportsPage","PluginReviewsSurface","PluginSiteSetPanel","PublishArtifactDialog","BUNDLE_ID","RATING_FIELD","RatingInput","registerMarketplaceConsole","registerCustomFieldType","Input","registerConsoleExtension","widgets","slot","widgetId","Component","orgNavItems","label","href","navTabId","icon","path","ownsSubtree","header","title","docsTopic","sections","id","landsOnQuery","permission","staffPages","pluginId","displayName","default","useMarketplaceActions","MarketplaceBrowse","HostPluginsCard"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,wBAAwB,QAAQ,2BAA0B;AACnE,SAASC,oBAAoB,QAAQ,yBAAwB;AAE7D,OAAOC,oBAAoB,4CAAwC;AACnE,OAAOC,4BAA4B,qDAAiD;AACpF,OAAOC,0BAA0B,mDAA+C;AAGhF,OAAOC,wBAAwB,kDAA8C;AAC7E,OAAOC,2BAA2B,oDAAgD;AAElF,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,YAAY,QAAQ,0BAAsB;AACnD,OAAOC,iBAAiB,yCAAqC;AAE7D;;;;;;;;;;;CAWC,GACD,OAAO,SAASC;IACd,wEAAwE;IACxEX,MAAMY,uBAAuB,CAAC,aAAKH;QAAcI,OAAOH;;IACxDV,MAAMc,wBAAwB,CAAC;QAC7B;;;;;;;;KAQC,GACDC,SAAS;YACP,qEAAqE;YACrE,sEAAsE;YACtE,4CAA4C;YAC5C;gBACEC,MAAM;gBACNC,UAAU;gBACVC,WAAWZ;YACb;YACA,mEAAmE;YACnE,uEAAuE;YACvE,uEAAuE;YACvE,wEAAwE;YACxE,uEAAuE;YACvE;gBACEU,MAAM;gBACNC,UAAU;gBACVC,WAAWX;YACb;SACD;QACD;;;;;;;;;;;;;;;;;KAiBC,GACDY,aAAa;YACX;gBACEC,OAAO;gBACPC,MAAM;gBACNC,UAAU;gBACVC,MAAM;oBAAEC,MAAMtB,qBAAqBsB,IAAI;gBAAC;gBACxCC,aAAa;gBACbP,WAAWf;gBACXuB,QAAQ;oBACNC,OAAO;oBACPJ,MAAM;wBAAEC,MAAMtB,qBAAqBsB,IAAI;oBAAC;oBACxCI,WAAW;gBACb;gBACAC,UAAU;oBACR,sDAAsD;oBACtD,kEAAkE;oBAClE,gCAAgC;oBAChC;wBAAEC,IAAI;wBAAUV,OAAO;oBAAa;oBACpC;wBAAEU,IAAI;wBAAaV,OAAO;oBAAY;oBACtC;;;;;;;;;;WAUC,GACD;wBACEU,IAAI;wBACJV,OAAO;wBACPW,cAAc;4BAAC;yBAAW;oBAC5B;oBACA;;;;;;WAMC,GACD;wBACED,IAAI;wBACJ,8DAA8D;wBAC9D,uBAAuB;wBACvBV,OAAO;wBACPY,YAAY;oBACd;oBACA;wBACEF,IAAI;wBACJ,+DAA+D;wBAC/D,YAAY;wBACZV,OAAO;wBACPY,YAAY;oBACd;oBACA;wBACEF,IAAI;wBACJV,OAAO;wBACPY,YAAY;oBACd;oBACA;wBACEF,IAAI;wBACJV,OAAO;wBACPY,YAAY;wBACZ,oDAAoD;wBACpD,2DAA2D;wBAC3DD,cAAc;4BAAC;yBAAU;oBAC3B;oBACA;wBACED,IAAI;wBACJV,OAAO;wBACPY,YAAY;oBACd;iBACD;YACH;SACD;QACD;;;;;;;;KAQC,GACDC,YAAY;YACV;gBACEH,IAAI;gBACJV,OAAO;gBACPM,QAAQ;oBACNC,OAAO;oBACPJ,MAAM;wBAAEC,MAAMvB,yBAAyBuB,IAAI;oBAAC;oBAC5C,8DAA8D;oBAC9D,mEAAmE;oBACnE,mCAAmC;oBACnCI,WAAW;gBACb;gBACAV,WAAWd;YACb;YACA;;;;;;;;;;;;OAYC,GACD;gBACE0B,IAAI;gBACJV,OAAO;gBACPK,aAAa;gBACbC,QAAQ;oBACNC,OAAO;oBACPJ,MAAM;wBAAEC,MAAMvB,yBAAyBuB,IAAI;oBAAC;oBAC5CI,WAAW;gBACb;gBACAV,WAAWb;YACb;SACD;QACD6B,UAAU1B;QACV2B,aAAa;IACf;AACF;AAEA,uDAAuD;AACvD,SAASC,WAAWC,qBAAqB,QAAQ,qCAAiC;AAClF,SAASD,WAAWE,iBAAiB,QAAQ,+CAA2C;AACxF,SAASF,WAAWG,eAAe,QAAQ,8CAA0C;AACrF,SAASH,WAAW9B,kBAAkB,QAAQ,kDAA8C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ declare function handler(request: Request): Promise<Response>;
18
+ export { handler as marketplaceAdminReports };