@aglyn/plugins-marketplace 1.0.0-beta.285 → 1.0.0-beta.287
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/lib/declarations.server.d.ts +2 -1
- package/src/lib/declarations.server.js +18 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/marketplace.d.ts +24 -0
- package/src/lib/model/marketplace.js.map +1 -1
- package/src/lib/model/site-starter-listing.d.ts +49 -0
- package/src/lib/model/site-starter-listing.js +75 -0
- package/src/lib/model/site-starter-listing.js.map +1 -0
- package/src/lib/server/publish-starter.d.ts +37 -0
- package/src/lib/server/publish-starter.js +501 -0
- package/src/lib/server/publish-starter.js.map +1 -0
- package/src/lib/server/site-starter-source.d.ts +19 -0
- package/src/lib/server/site-starter-source.js +189 -0
- package/src/lib/server/site-starter-source.js.map +1 -0
- package/src/lib/server.js +3 -0
- package/src/lib/server.js.map +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { PluginSiteStarterSource } from '@aglyn/aglyn/plugin-manager/plugin-site-starters';
|
|
18
|
+
/** The marketplace's `core.site-starters` source (AGL-4049). */
|
|
19
|
+
export declare const marketplaceSiteStarterSource: Required<PluginSiteStarterSource>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { matchSiteStarterFacets, SITE_STARTER_ARTIFACT_TYPE, siteStarterFacetsOf, siteStarterRefusal } from "@aglyn/aglyn/app-utils/site-starter";
|
|
18
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
19
|
+
import { BROWSE_EVERYONE, LISTING_BROWSE_AUDIENCE, LISTING_BROWSE_TOKENS } from "../model/listing-query.js";
|
|
20
|
+
import { isListingBrowsable, isListingDeleted, isPrivateListing, listingArtifactType } from "../model/marketplace.js";
|
|
21
|
+
import { officialStartersFirst, SITE_STARTER_KNOWN_IDS, siteStarterSearchLimit, siteStarterSearchTokens, siteStarterSummaryOf } from "../model/site-starter-listing.js";
|
|
22
|
+
import { canActAsPublisher, PUBLISHER_PROFILES } from "./publisher-profile.js";
|
|
23
|
+
import { requirePurchase } from "./purchase-entitlement.js";
|
|
24
|
+
import { isPublisherSecurityLocked } from "./sale-risk.js";
|
|
25
|
+
import { recordVersionMove } from "./version-stats.js";
|
|
26
|
+
/**
|
|
27
|
+
* Where the console's "Create site" finds its starters (AGL-4049): the
|
|
28
|
+
* marketplace's `siteStarter` listings, behind core's `core.site-starters`
|
|
29
|
+
* seam (`plugin-manager/plugin-site-starters.ts`), registered from
|
|
30
|
+
* `declarations.server.ts`.
|
|
31
|
+
*
|
|
32
|
+
* `resolve` is a content door like the install routes: it hands over a
|
|
33
|
+
* listing's stored version, so it refuses what they refuse — a taken-down
|
|
34
|
+
* listing, a publisher under a security lock, a private listing to anyone
|
|
35
|
+
* but its own workspace, an unpaid priced one (`install-listing-gates.spec.ts`
|
|
36
|
+
* holds the three). A starter still in review is its own workspace's to try,
|
|
37
|
+
* as a plugin is.
|
|
38
|
+
*/ const LISTINGS = 'marketplaceListings';
|
|
39
|
+
const firestoreOf = ()=>firebaseAdmin.app().firestore();
|
|
40
|
+
const gone = (error = 'Unknown starter')=>({
|
|
41
|
+
error,
|
|
42
|
+
status: 404
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Each publisher's name as a search card shows it, read once per publisher
|
|
46
|
+
* in one batch: the profile's display name, else its handle.
|
|
47
|
+
*/ async function authorNames(firestore, profileIds) {
|
|
48
|
+
const ids = [
|
|
49
|
+
...new Set(profileIds.filter((id)=>typeof id === 'string' && id))
|
|
50
|
+
];
|
|
51
|
+
const names = new Map();
|
|
52
|
+
if (!ids.length) return names;
|
|
53
|
+
const refs = ids.map((id)=>firestore.collection(PUBLISHER_PROFILES).doc(id));
|
|
54
|
+
const snapshots = await firestore.getAll(...refs);
|
|
55
|
+
snapshots.forEach((snapshot, index)=>{
|
|
56
|
+
const displayName = snapshot.get('displayName');
|
|
57
|
+
const handle = snapshot.get('handle');
|
|
58
|
+
const name = typeof displayName === 'string' && displayName.trim() ? displayName.trim() : typeof handle === 'string' ? handle : '';
|
|
59
|
+
names.set(ids[index], name);
|
|
60
|
+
});
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* What anyone may see: the search asks the public audience only, so who is
|
|
65
|
+
* asking changes nothing about the answer and the viewer is not read.
|
|
66
|
+
*/ async function search(input) {
|
|
67
|
+
var _ref;
|
|
68
|
+
const limit = siteStarterSearchLimit(input == null ? void 0 : input.limit);
|
|
69
|
+
if (!limit) return [];
|
|
70
|
+
const filter = (_ref = input == null ? void 0 : input.filter) != null ? _ref : {};
|
|
71
|
+
const firestore = firestoreOf();
|
|
72
|
+
let query = firestore.collection(LISTINGS).where('artifactType', '==', SITE_STARTER_ARTIFACT_TYPE);
|
|
73
|
+
if (filter.mode === 'base' || filter.mode === 'ai') {
|
|
74
|
+
query = query.where('starterMode', '==', filter.mode);
|
|
75
|
+
}
|
|
76
|
+
if (typeof filter.kind === 'string' && filter.kind) {
|
|
77
|
+
query = query.where('starterKind', '==', filter.kind);
|
|
78
|
+
}
|
|
79
|
+
if (typeof filter.base === 'string' && filter.base) {
|
|
80
|
+
query = query.where('starterBase', '==', filter.base);
|
|
81
|
+
}
|
|
82
|
+
// One array clause answers who may see it, and the search folds into it:
|
|
83
|
+
// `browseTokens` holds only `scope~word` pairs, never the bare scope.
|
|
84
|
+
const tokens = siteStarterSearchTokens(input == null ? void 0 : input.word);
|
|
85
|
+
query = tokens.length ? query.where(LISTING_BROWSE_TOKENS, 'array-contains-any', tokens) : query.where(LISTING_BROWSE_AUDIENCE, 'array-contains', BROWSE_EVERYONE);
|
|
86
|
+
// Twice the page, so what the facets the query cannot ask (fonts, pages)
|
|
87
|
+
// filter out in memory still leaves a full one, most of the time.
|
|
88
|
+
const snapshot = await query.orderBy('createdAt', 'desc').limit(limit * 2).get();
|
|
89
|
+
const rows = snapshot.docs.map((doc)=>{
|
|
90
|
+
var _doc_data;
|
|
91
|
+
return {
|
|
92
|
+
id: doc.id,
|
|
93
|
+
listing: (_doc_data = doc.data()) != null ? _doc_data : {}
|
|
94
|
+
};
|
|
95
|
+
})// Defense in depth: the audience clause already admits only these.
|
|
96
|
+
.filter(({ listing })=>!isListingDeleted(listing) && isListingBrowsable(listing)).filter(({ listing })=>matchSiteStarterFacets(siteStarterFacetsOf(listing), filter));
|
|
97
|
+
const ordered = officialStartersFirst(rows.map((row)=>_extends({}, row, {
|
|
98
|
+
official: row.listing['official'] === true
|
|
99
|
+
}))).slice(0, limit);
|
|
100
|
+
const names = await authorNames(firestore, ordered.map(({ listing })=>{
|
|
101
|
+
var _listing_profileId;
|
|
102
|
+
return String((_listing_profileId = listing['profileId']) != null ? _listing_profileId : '');
|
|
103
|
+
}));
|
|
104
|
+
return ordered.map(({ id, listing })=>{
|
|
105
|
+
var _names_get, _listing_profileId;
|
|
106
|
+
return siteStarterSummaryOf(id, listing, (_names_get = names.get(String((_listing_profileId = listing['profileId']) != null ? _listing_profileId : ''))) != null ? _names_get : '');
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async function resolve(choice, viewer) {
|
|
110
|
+
var _listing_profileId, _ref, _ref1, _listing_priceUsd, _ref2, _ref3, _choice_version;
|
|
111
|
+
const listingId = typeof (choice == null ? void 0 : choice.listingId) === 'string' ? choice.listingId : '';
|
|
112
|
+
if (!listingId) return gone();
|
|
113
|
+
const firestore = firestoreOf();
|
|
114
|
+
const listingRef = firestore.collection(LISTINGS).doc(listingId);
|
|
115
|
+
const listing = (await listingRef.get()).data();
|
|
116
|
+
if (!listing || listing.deletedAt || // A staff takedown hands nothing over, to anyone (AGL-2290).
|
|
117
|
+
listing.hiddenAt || // Nor does a publisher under a security lock (AGL-3365).
|
|
118
|
+
await isPublisherSecurityLocked(firestore, listing.profileId) || listingArtifactType(listing) !== SITE_STARTER_ARTIFACT_TYPE) {
|
|
119
|
+
return gone();
|
|
120
|
+
}
|
|
121
|
+
// The publisher's own workspace picks its own starter free, and only into
|
|
122
|
+
// itself: the waiver is about the publisher's OWN sites (AGL-2484), so a
|
|
123
|
+
// person who administers the publisher and creates a site elsewhere is a
|
|
124
|
+
// buyer like anyone else there.
|
|
125
|
+
const publisherOrgId = String((_listing_profileId = listing.profileId) != null ? _listing_profileId : '');
|
|
126
|
+
const viewerOrgId = String((_ref = viewer == null ? void 0 : viewer.orgId) != null ? _ref : '');
|
|
127
|
+
const ownsListing = viewerOrgId ? publisherOrgId !== '' && viewerOrgId === publisherOrgId && await canActAsPublisher(firestore, String((_ref1 = viewer == null ? void 0 : viewer.uid) != null ? _ref1 : ''), listing.profileId) : false;
|
|
128
|
+
// Private means its own workspace only (AGL-968).
|
|
129
|
+
if (isPrivateListing(listing) && !ownsListing) return gone();
|
|
130
|
+
// A starter still in review, or rejected, is its publisher's to try.
|
|
131
|
+
if (!isListingBrowsable(listing) && !ownsListing) return gone();
|
|
132
|
+
const priceUsd = Number((_listing_priceUsd = listing.priceUsd) != null ? _listing_priceUsd : 0);
|
|
133
|
+
const unpaid = await requirePurchase({
|
|
134
|
+
firestore,
|
|
135
|
+
buyerUid: String((_ref2 = viewer == null ? void 0 : viewer.uid) != null ? _ref2 : ''),
|
|
136
|
+
buyerOrgId: viewerOrgId,
|
|
137
|
+
listingId,
|
|
138
|
+
priceUsd,
|
|
139
|
+
ownsListing
|
|
140
|
+
});
|
|
141
|
+
if (unpaid) return {
|
|
142
|
+
error: unpaid.error,
|
|
143
|
+
status: 402,
|
|
144
|
+
priceUsd: unpaid.priceUsd
|
|
145
|
+
};
|
|
146
|
+
const version = String((_ref3 = (_choice_version = choice.version) != null ? _choice_version : listing.latestVersion) != null ? _ref3 : '');
|
|
147
|
+
if (!version) return gone();
|
|
148
|
+
const versionSnapshot = await listingRef.collection('versions').doc(version).get();
|
|
149
|
+
const payload = versionSnapshot.get('starter');
|
|
150
|
+
if (!payload || typeof payload !== 'object') return gone();
|
|
151
|
+
// A starter that cannot start a site is gone, as far as a buyer is concerned.
|
|
152
|
+
const refusal = siteStarterRefusal(payload, SITE_STARTER_KNOWN_IDS);
|
|
153
|
+
if (refusal) return gone(refusal);
|
|
154
|
+
return payload;
|
|
155
|
+
}
|
|
156
|
+
async function installed(choice, _viewer, site) {
|
|
157
|
+
try {
|
|
158
|
+
var _choice_version;
|
|
159
|
+
const listingId = typeof (choice == null ? void 0 : choice.listingId) === 'string' ? choice.listingId : '';
|
|
160
|
+
if (!listingId) return;
|
|
161
|
+
const firestore = firestoreOf();
|
|
162
|
+
const listingRef = firestore.collection(LISTINGS).doc(listingId);
|
|
163
|
+
const latest = (_choice_version = choice.version) != null ? _choice_version : (await listingRef.get()).get('latestVersion');
|
|
164
|
+
await recordVersionMove({
|
|
165
|
+
firestore,
|
|
166
|
+
listingRef,
|
|
167
|
+
artifactType: SITE_STARTER_ARTIFACT_TYPE,
|
|
168
|
+
from: null,
|
|
169
|
+
to: latest != null ? latest : null
|
|
170
|
+
});
|
|
171
|
+
await listingRef.update({
|
|
172
|
+
installCount: firebaseAdmin.firestore.FieldValue.increment(1)
|
|
173
|
+
});
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Counting never fails the site it counts.
|
|
176
|
+
console.error('site starter install count failed', {
|
|
177
|
+
listingId: choice == null ? void 0 : choice.listingId,
|
|
178
|
+
hostId: site == null ? void 0 : site.hostId,
|
|
179
|
+
error
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** The marketplace's `core.site-starters` source (AGL-4049). */ export const marketplaceSiteStarterSource = {
|
|
184
|
+
search,
|
|
185
|
+
resolve,
|
|
186
|
+
installed
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
//# sourceMappingURL=site-starter-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/server/site-starter-source.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 {\n matchSiteStarterFacets,\n SITE_STARTER_ARTIFACT_TYPE,\n siteStarterFacetsOf,\n siteStarterRefusal,\n type SiteStarterChoice,\n type SiteStarterFacets,\n type SiteStarterPayload,\n} from '@aglyn/aglyn/app-utils/site-starter'\nimport type {\n PluginSiteStarterSource,\n SiteStarterSummary,\n SiteStarterViewer,\n} from '@aglyn/aglyn/plugin-manager/plugin-site-starters'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport {\n BROWSE_EVERYONE,\n LISTING_BROWSE_AUDIENCE,\n LISTING_BROWSE_TOKENS,\n} from '../model/listing-query'\nimport {\n isListingBrowsable,\n isListingDeleted,\n isPrivateListing,\n listingArtifactType,\n} from '../model/marketplace'\nimport {\n officialStartersFirst,\n SITE_STARTER_KNOWN_IDS,\n siteStarterSearchLimit,\n siteStarterSearchTokens,\n siteStarterSummaryOf,\n} from '../model/site-starter-listing'\nimport { canActAsPublisher, PUBLISHER_PROFILES } from './publisher-profile'\nimport { requirePurchase } from './purchase-entitlement'\nimport { isPublisherSecurityLocked } from './sale-risk'\nimport { recordVersionMove } from './version-stats'\n\n/**\n * Where the console's \"Create site\" finds its starters (AGL-4049): the\n * marketplace's `siteStarter` listings, behind core's `core.site-starters`\n * seam (`plugin-manager/plugin-site-starters.ts`), registered from\n * `declarations.server.ts`.\n *\n * `resolve` is a content door like the install routes: it hands over a\n * listing's stored version, so it refuses what they refuse — a taken-down\n * listing, a publisher under a security lock, a private listing to anyone\n * but its own workspace, an unpaid priced one (`install-listing-gates.spec.ts`\n * holds the three). A starter still in review is its own workspace's to try,\n * as a plugin is.\n */\n\nconst LISTINGS = 'marketplaceListings'\n\nconst firestoreOf = () => firebaseAdmin.app().firestore()\n\ntype ListingDoc = Record<string, any>\n\n/** The answer a refused pick gives, in the seam's shape. */\ntype Refused = { error: string; status: 402 | 403 | 404; priceUsd?: number }\n\nconst gone = (error = 'Unknown starter'): Refused => ({ error, status: 404 })\n\n/**\n * Each publisher's name as a search card shows it, read once per publisher\n * in one batch: the profile's display name, else its handle.\n */\nasync function authorNames(\n firestore: FirebaseFirestore.Firestore,\n profileIds: readonly string[],\n): Promise<Map<string, string>> {\n const ids = [...new Set(profileIds.filter((id) => typeof id === 'string' && id))]\n const names = new Map<string, string>()\n if (!ids.length) return names\n const refs = ids.map((id) => firestore.collection(PUBLISHER_PROFILES).doc(id))\n const snapshots = await firestore.getAll(...refs)\n snapshots.forEach((snapshot, index) => {\n const displayName = snapshot.get('displayName')\n const handle = snapshot.get('handle')\n const name =\n typeof displayName === 'string' && displayName.trim()\n ? displayName.trim()\n : typeof handle === 'string'\n ? handle\n : ''\n names.set(ids[index], name)\n })\n return names\n}\n\n/**\n * What anyone may see: the search asks the public audience only, so who is\n * asking changes nothing about the answer and the viewer is not read.\n */\nasync function search(\n input: { word: string; filter: Partial<SiteStarterFacets>; limit: number },\n): Promise<SiteStarterSummary[]> {\n const limit = siteStarterSearchLimit(input?.limit)\n if (!limit) return []\n const filter: Partial<SiteStarterFacets> = input?.filter ?? {}\n const firestore = firestoreOf()\n\n let query: FirebaseFirestore.Query = firestore\n .collection(LISTINGS)\n .where('artifactType', '==', SITE_STARTER_ARTIFACT_TYPE)\n if (filter.mode === 'base' || filter.mode === 'ai') {\n query = query.where('starterMode', '==', filter.mode)\n }\n if (typeof filter.kind === 'string' && filter.kind) {\n query = query.where('starterKind', '==', filter.kind)\n }\n if (typeof filter.base === 'string' && filter.base) {\n query = query.where('starterBase', '==', filter.base)\n }\n // One array clause answers who may see it, and the search folds into it:\n // `browseTokens` holds only `scope~word` pairs, never the bare scope.\n const tokens = siteStarterSearchTokens(input?.word)\n query = tokens.length\n ? query.where(LISTING_BROWSE_TOKENS, 'array-contains-any', tokens)\n : query.where(LISTING_BROWSE_AUDIENCE, 'array-contains', BROWSE_EVERYONE)\n // Twice the page, so what the facets the query cannot ask (fonts, pages)\n // filter out in memory still leaves a full one, most of the time.\n const snapshot = await query.orderBy('createdAt', 'desc').limit(limit * 2).get()\n\n const rows = snapshot.docs\n .map((doc) => ({ id: doc.id, listing: (doc.data() ?? {}) as ListingDoc }))\n // Defense in depth: the audience clause already admits only these.\n .filter(({ listing }) => !isListingDeleted(listing) && isListingBrowsable(listing))\n .filter(({ listing }) => matchSiteStarterFacets(siteStarterFacetsOf(listing), filter))\n const ordered = officialStartersFirst(\n rows.map((row) => ({ ...row, official: row.listing['official'] === true })),\n ).slice(0, limit)\n const names = await authorNames(\n firestore,\n ordered.map(({ listing }) => String(listing['profileId'] ?? '')),\n )\n return ordered.map(({ id, listing }) =>\n siteStarterSummaryOf(id, listing, names.get(String(listing['profileId'] ?? '')) ?? ''),\n )\n}\n\nasync function resolve(\n choice: SiteStarterChoice,\n viewer: SiteStarterViewer,\n): Promise<SiteStarterPayload | Refused> {\n const listingId = typeof choice?.listingId === 'string' ? choice.listingId : ''\n if (!listingId) return gone()\n const firestore = firestoreOf()\n const listingRef = firestore.collection(LISTINGS).doc(listingId)\n const listing = (await listingRef.get()).data() as ListingDoc | undefined\n if (\n !listing ||\n listing.deletedAt ||\n // A staff takedown hands nothing over, to anyone (AGL-2290).\n listing.hiddenAt ||\n // Nor does a publisher under a security lock (AGL-3365).\n (await isPublisherSecurityLocked(firestore, listing.profileId)) ||\n listingArtifactType(listing) !== SITE_STARTER_ARTIFACT_TYPE\n ) {\n return gone()\n }\n\n // The publisher's own workspace picks its own starter free, and only into\n // itself: the waiver is about the publisher's OWN sites (AGL-2484), so a\n // person who administers the publisher and creates a site elsewhere is a\n // buyer like anyone else there.\n const publisherOrgId = String(listing.profileId ?? '')\n const viewerOrgId = String(viewer?.orgId ?? '')\n const ownsListing = viewerOrgId\n ? publisherOrgId !== '' &&\n viewerOrgId === publisherOrgId &&\n (await canActAsPublisher(firestore, String(viewer?.uid ?? ''), listing.profileId))\n : false\n // Private means its own workspace only (AGL-968).\n if (isPrivateListing(listing) && !ownsListing) return gone()\n // A starter still in review, or rejected, is its publisher's to try.\n if (!isListingBrowsable(listing) && !ownsListing) return gone()\n\n const priceUsd = Number(listing.priceUsd ?? 0)\n const unpaid = await requirePurchase({\n firestore,\n buyerUid: String(viewer?.uid ?? ''),\n buyerOrgId: viewerOrgId,\n listingId,\n priceUsd,\n ownsListing,\n })\n if (unpaid) return { error: unpaid.error, status: 402, priceUsd: unpaid.priceUsd }\n\n const version = String(choice.version ?? listing.latestVersion ?? '')\n if (!version) return gone()\n const versionSnapshot = await listingRef.collection('versions').doc(version).get()\n const payload = versionSnapshot.get('starter') as SiteStarterPayload | undefined\n if (!payload || typeof payload !== 'object') return gone()\n // A starter that cannot start a site is gone, as far as a buyer is concerned.\n const refusal = siteStarterRefusal(payload, SITE_STARTER_KNOWN_IDS)\n if (refusal) return gone(refusal)\n return payload\n}\n\nasync function installed(\n choice: SiteStarterChoice,\n _viewer: SiteStarterViewer,\n site: { hostId: string },\n): Promise<void> {\n try {\n const listingId = typeof choice?.listingId === 'string' ? choice.listingId : ''\n if (!listingId) return\n const firestore = firestoreOf()\n const listingRef = firestore.collection(LISTINGS).doc(listingId)\n const latest = choice.version ?? (await listingRef.get()).get('latestVersion')\n await recordVersionMove({\n firestore,\n listingRef,\n artifactType: SITE_STARTER_ARTIFACT_TYPE,\n from: null,\n to: latest ?? null,\n })\n await listingRef.update({\n installCount: firebaseAdmin.firestore.FieldValue.increment(1),\n })\n } catch (error) {\n // Counting never fails the site it counts.\n console.error('site starter install count failed', {\n listingId: choice?.listingId,\n hostId: site?.hostId,\n error,\n })\n }\n}\n\n/** The marketplace's `core.site-starters` source (AGL-4049). */\nexport const marketplaceSiteStarterSource: Required<PluginSiteStarterSource> = {\n search,\n resolve,\n installed,\n}\n"],"names":["matchSiteStarterFacets","SITE_STARTER_ARTIFACT_TYPE","siteStarterFacetsOf","siteStarterRefusal","firebaseAdmin","BROWSE_EVERYONE","LISTING_BROWSE_AUDIENCE","LISTING_BROWSE_TOKENS","isListingBrowsable","isListingDeleted","isPrivateListing","listingArtifactType","officialStartersFirst","SITE_STARTER_KNOWN_IDS","siteStarterSearchLimit","siteStarterSearchTokens","siteStarterSummaryOf","canActAsPublisher","PUBLISHER_PROFILES","requirePurchase","isPublisherSecurityLocked","recordVersionMove","LISTINGS","firestoreOf","app","firestore","gone","error","status","authorNames","profileIds","ids","Set","filter","id","names","Map","length","refs","map","collection","doc","snapshots","getAll","forEach","snapshot","index","displayName","get","handle","name","trim","set","search","input","limit","query","where","mode","kind","base","tokens","word","orderBy","rows","docs","listing","data","ordered","row","official","slice","String","resolve","choice","viewer","listingId","listingRef","deletedAt","hiddenAt","profileId","publisherOrgId","viewerOrgId","orgId","ownsListing","uid","priceUsd","Number","unpaid","buyerUid","buyerOrgId","version","latestVersion","versionSnapshot","payload","refusal","installed","_viewer","site","latest","artifactType","from","to","update","installCount","FieldValue","increment","console","hostId","marketplaceSiteStarterSource"],"mappings":"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"}
|
package/src/lib/server.js
CHANGED
|
@@ -53,6 +53,7 @@ import { publishDatasetSchemaHandler } from "./server/publish-dataset-schema.js"
|
|
|
53
53
|
import { publishEmailStarterHandler } from "./server/publish-email-starter.js";
|
|
54
54
|
import { publishEmailTemplateHandler } from "./server/publish-email-template.js";
|
|
55
55
|
import { publishLayoutHandler } from "./server/publish-layout.js";
|
|
56
|
+
import { publishStarterHandler } from "./server/publish-starter.js";
|
|
56
57
|
import { publishTemplateHandler } from "./server/publish-template.js";
|
|
57
58
|
import { publishThemeHandler } from "./server/publish-theme.js";
|
|
58
59
|
import { updateArtifactHandler } from "./server/update-artifact.js";
|
|
@@ -174,6 +175,8 @@ import { updateArtifactHandler } from "./server/update-artifact.js";
|
|
|
174
175
|
registerPluginApiRoute('marketplace/verification-request', verificationRequestHandler);
|
|
175
176
|
registerPluginApiRoute('marketplace/publish-layout', publishLayoutHandler);
|
|
176
177
|
registerPluginApiRoute('marketplace/publish-template', publishTemplateHandler);
|
|
178
|
+
// A whole site as a site starter, picked in "Create site" (AGL-4049).
|
|
179
|
+
registerPluginApiRoute('marketplace/publish-starter', publishStarterHandler);
|
|
177
180
|
registerPluginApiRoute('marketplace/publish-theme', publishThemeHandler);
|
|
178
181
|
registerPluginApiRoute('marketplace/publish-dataset-schema', publishDatasetSchemaHandler);
|
|
179
182
|
registerPluginApiRoute('marketplace/publish-email-starter', publishEmailStarterHandler);
|
package/src/lib/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerCustomFieldType,\n} from '@aglyn/aglyn/server'\n// Its own subpath, never the plugin-manager barrel: what a published page\n// does not need, it must not import.\nimport { registerPluginRouteMetadata } from '@aglyn/aglyn/plugin-manager/plugin-route-metadata'\nimport { registerPluginArtifactInventory } from '@aglyn/aglyn/plugin-manager/plugin-artifact-inventory'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { marketplaceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerMarketplaceLockdown } from './server/publisher-lockdown'\nimport { publishPluginHandler } from './server/publish-plugin'\nimport { verificationRequestHandler } from './server/verification-request'\nimport { checkoutHandler } from './server/checkout'\nimport { connectHandler } from './server/connect'\nimport { installHandler } from './server/install'\nimport { installPluginHandler } from './server/install-plugin'\nimport { listingVersionsHandler } from './server/listing-versions'\nimport { RATING_FIELD } from './model/rating-field'\nimport { installDatasetSchemaHandler } from './server/install-dataset-schema'\nimport { installEmailStarterHandler } from './server/install-email-starter'\nimport { installEmailTemplateHandler } from './server/install-email-template'\nimport { installLayoutHandler } from './server/install-layout'\nimport { installTemplateHandler } from './server/install-template'\nimport { installThemeHandler } from './server/install-theme'\nimport { previewImageHandler } from './server/preview-image'\nimport { publishHandler } from './server/publish'\nimport { marketplaceArtifactInventory } from './server/artifact-inventory'\nimport { marketplaceTaxReturnSource } from './server/tax-return-source'\nimport { marketplaceRevenueSource } from './server/revenue-source'\nimport { marketplaceAdminReports } from './server/admin-reports'\nimport { marketplaceAdminReviews } from './server/admin-reviews'\nimport { marketplaceAdminOverview } from './server/admin-overview'\nimport { marketplaceAdminTrust } from './server/admin-trust'\nimport { reportHandler } from './server/report'\nimport { reviewsHandler } from './server/reviews'\nimport { publisherProfileSaveHandler } from './server/publisher-profile-save'\nimport { publishDatasetSchemaHandler } from './server/publish-dataset-schema'\nimport { publishEmailStarterHandler } from './server/publish-email-starter'\nimport { publishEmailTemplateHandler } from './server/publish-email-template'\nimport { publishLayoutHandler } from './server/publish-layout'\nimport { publishTemplateHandler } from './server/publish-template'\nimport { publishThemeHandler } from './server/publish-theme'\nimport { updateArtifactHandler } from './server/update-artifact'\n\n/**\n * Registers the marketplace plugin's console-side API routes (AGL-396):\n * marketplace publish/install of templates and plugins, and the Stripe\n * Connect + checkout flows for paid listings.\n *\n * Upload-bodied routes register here too. The note that used to sit here —\n * that they had to stay as named console routes because the dispatcher\n * \"can't grant per-route bodyParser limits\" — was a Pages Router leftover:\n * `runLegacyHandler` reads the request through the same\n * `pluginRequestFromWeb` a named App Router route would, and imposes no\n * limit of its own. publish-plugin's 8 MB bundle has been going through the\n * dispatcher the whole time.\n */\nexport function registerMarketplaceConsoleApi(): void {\n // Server side of the rating custom field (AGL-434): validators run\n // on import/write paths even when no client loaded the plugin.\n registerCustomFieldType(RATING_FIELD)\n /*\n * What a listing link unfurls as (AGL-876, handed to the platform by\n * AGL-3080).\n *\n * The card used to be built by a hand-written console route with a server\n * layout of its own, which is what kept that route out of the generic\n * plugin route — moving it would have dropped every listing's card with\n * nothing red. The shell asks this instead, so the card survives the move\n * and no console file reads `marketplaceListings` to build a head.\n *\n * One segment and one only: `/{org}/marketplace/{listingId}`. The hub, the\n * publish page and every other address under this route answer `null`,\n * which leaves the shell's own title exactly as it was.\n */\n registerPluginRouteMetadata(\n {\n route: 'marketplace',\n resolve: async (segments) => {\n if (segments.length !== 1) return null\n const { readListingForSocialCard } = await import(\n './server/listing-social-card.server'\n )\n const { listingSocialCard } = await import('./model/listing-social-card')\n return listingSocialCard(await readListingForSocialCard(segments[0]))\n },\n },\n // Named, because this registrar is called directly by the app's server\n // loader rather than from inside a plugin `register` fn, where the\n // loader's owner marker would be set.\n { pluginId: BUNDLE_ID },\n )\n /*\n * Who claims the bytes in the artifacts bucket (AGL-3080).\n *\n * The platform's two scheduled sweeps run from `/api/admin` routes that\n * used to walk `pluginVersions` and `marketplaceListings` themselves. They\n * ask here now — and an unregistered inventory REFUSES both runs rather\n * than reporting an empty bucket, which is the whole point of the\n * contract's shape.\n */\n registerPluginArtifactInventory(marketplaceArtifactInventory, {\n pluginId: BUNDLE_ID,\n })\n /*\n * Its sales on the operator's own sales tax return (AGL-3080): the tax a\n * marketplace charge adds on the platform's own account. The staff return\n * awaits this surface before it asks, and refuses to be filed without this\n * source — the marketplace declares `taxReturnSource`.\n */\n registerTaxReturnSource(marketplaceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the commission its sales earn the operator, on the staff revenue\n // report — declared `revenueSource`, so a missing registration is named as\n // unread there rather than counted as zero.\n registerRevenueSource(marketplaceRevenueSource, { pluginId: BUNDLE_ID })\n registerPluginApiRoute('marketplace/checkout', checkoutHandler)\n registerPluginApiRoute('marketplace/connect', connectHandler)\n registerPluginApiRoute('marketplace/install', installHandler)\n registerPluginApiRoute('marketplace/install-plugin', installPluginHandler)\n registerPluginApiRoute('marketplace/install-layout', installLayoutHandler)\n registerPluginApiRoute('marketplace/install-template', installTemplateHandler)\n // A theme install DOES change the running site (AGL-1020) — it is the site's\n // appearance — so this route also owns the ways back: `revert` and `reset`.\n registerPluginApiRoute('marketplace/install-theme', installThemeHandler)\n registerPluginApiRoute(\n 'marketplace/install-dataset-schema',\n installDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-starter',\n installEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-template',\n installEmailTemplateHandler,\n )\n // Updating a copied artifact is its own route (AGL-1018), not a flag on\n // install: install writes the publisher's version, this one reconciles it\n // with a copy that has diverged and refuses to overwrite silently.\n registerPluginApiRoute('marketplace/update-artifact', updateArtifactHandler)\n registerPluginApiRoute('marketplace/listing-versions', listingVersionsHandler)\n registerPluginApiRoute('marketplace/preview-image', previewImageHandler)\n registerPluginApiRoute('marketplace/publish', publishHandler)\n registerPluginApiRoute('marketplace/report', reportHandler)\n /*\n * The staff end of that button (AGL-2310), moved out of\n * `apps/console/app/api/admin/` by AGL-3080. `web:` because it is a plain\n * fetch from this plugin's own staff page, not a plugin-request handler —\n * the same shape the AI plugin's `ai/admin/*` routes use, and for the same\n * reason: a staff route names no host, so there is no subject to resolve.\n */\n registerPluginApiRoute('marketplace/admin/reports', {\n web: marketplaceAdminReports,\n })\n // The review queue (AGL-432, moved by AGL-3080). Same shape and the same\n // reason: a staff route names no host, so there is no subject to resolve.\n registerPluginApiRoute('marketplace/admin/reviews', {\n web: marketplaceAdminReviews,\n })\n // Realm trust (AGL-420, moved by AGL-3080). Super-staff only, and the\n // SIGNATURE comes from the shell — the key is the console's and stays\n // there. See `server/admin-trust.ts`.\n registerPluginApiRoute('marketplace/admin/trust', {\n web: marketplaceAdminTrust,\n })\n // The staff overview's marketplace cards (AGL-3080): purchases and the\n // refund-reversal recovery queue. Staff-gated like the queues above.\n registerPluginApiRoute('marketplace/admin/overview', {\n web: marketplaceAdminOverview,\n })\n registerPluginApiRoute('marketplace/reviews', reviewsHandler)\n registerPluginApiRoute(\n 'marketplace/publisher-profile',\n publisherProfileSaveHandler,\n )\n registerPluginApiRoute(\n 'marketplace/verification-request',\n verificationRequestHandler,\n )\n registerPluginApiRoute('marketplace/publish-layout', publishLayoutHandler)\n registerPluginApiRoute('marketplace/publish-template', publishTemplateHandler)\n registerPluginApiRoute('marketplace/publish-theme', publishThemeHandler)\n registerPluginApiRoute(\n 'marketplace/publish-dataset-schema',\n publishDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-starter',\n publishEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-template',\n publishEmailTemplateHandler,\n )\n // Relocated console routes (AGL-418): URLs preserved via the dispatcher.\n registerPluginApiRoute('marketplace/publish-plugin', publishPluginHandler)\n // Marketplace purchases ride the platform Stripe webhook (AGL-418).\n registerBillingWebhookHandler(marketplaceBillingWebhookHandler)\n // A workspace lock reaches the publisher's payout account and its\n // listings (AGL-3365).\n registerMarketplaceLockdown()\n}\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { marketplacePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerCustomFieldType","registerPluginRouteMetadata","registerPluginArtifactInventory","registerTaxReturnSource","registerRevenueSource","BUNDLE_ID","marketplaceBillingWebhookHandler","registerMarketplaceLockdown","publishPluginHandler","verificationRequestHandler","checkoutHandler","connectHandler","installHandler","installPluginHandler","listingVersionsHandler","RATING_FIELD","installDatasetSchemaHandler","installEmailStarterHandler","installEmailTemplateHandler","installLayoutHandler","installTemplateHandler","installThemeHandler","previewImageHandler","publishHandler","marketplaceArtifactInventory","marketplaceTaxReturnSource","marketplaceRevenueSource","marketplaceAdminReports","marketplaceAdminReviews","marketplaceAdminOverview","marketplaceAdminTrust","reportHandler","reviewsHandler","publisherProfileSaveHandler","publishDatasetSchemaHandler","publishEmailStarterHandler","publishEmailTemplateHandler","publishLayoutHandler","publishTemplateHandler","publishThemeHandler","updateArtifactHandler","registerMarketplaceConsoleApi","route","resolve","segments","length","readListingForSocialCard","listingSocialCard","pluginId","web"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,6BAA6B,EAC7BC,sBAAsB,EACtBC,uBAAuB,QAClB,sBAAqB;AAC5B,0EAA0E;AAC1E,qCAAqC;AACrC,SAASC,2BAA2B,QAAQ,oDAAmD;AAC/F,SAASC,+BAA+B,QAAQ,wDAAuD;AACvG,SAASC,uBAAuB,QAAQ,wDAAuD;AAC/F,SAASC,qBAAqB,QAAQ,qDAAoD;AAC1F,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,gCAAgC,QAAQ,8BAA0B;AAC3E,SAASC,2BAA2B,QAAQ,iCAA6B;AACzE,SAASC,oBAAoB,QAAQ,6BAAyB;AAC9D,SAASC,0BAA0B,QAAQ,mCAA+B;AAC1E,SAASC,eAAe,QAAQ,uBAAmB;AACnD,SAASC,cAAc,QAAQ,sBAAkB;AACjD,SAASC,cAAc,QAAQ,sBAAkB;AACjD,SAASC,oBAAoB,QAAQ,6BAAyB;AAC9D,SAASC,sBAAsB,QAAQ,+BAA2B;AAClE,SAASC,YAAY,QAAQ,0BAAsB;AACnD,SAASC,2BAA2B,QAAQ,qCAAiC;AAC7E,SAASC,0BAA0B,QAAQ,oCAAgC;AAC3E,SAASC,2BAA2B,QAAQ,qCAAiC;AAC7E,SAASC,oBAAoB,QAAQ,6BAAyB;AAC9D,SAASC,sBAAsB,QAAQ,+BAA2B;AAClE,SAASC,mBAAmB,QAAQ,4BAAwB;AAC5D,SAASC,mBAAmB,QAAQ,4BAAwB;AAC5D,SAASC,cAAc,QAAQ,sBAAkB;AACjD,SAASC,4BAA4B,QAAQ,iCAA6B;AAC1E,SAASC,0BAA0B,QAAQ,gCAA4B;AACvE,SAASC,wBAAwB,QAAQ,6BAAyB;AAClE,SAASC,uBAAuB,QAAQ,4BAAwB;AAChE,SAASC,uBAAuB,QAAQ,4BAAwB;AAChE,SAASC,wBAAwB,QAAQ,6BAAyB;AAClE,SAASC,qBAAqB,QAAQ,0BAAsB;AAC5D,SAASC,aAAa,QAAQ,qBAAiB;AAC/C,SAASC,cAAc,QAAQ,sBAAkB;AACjD,SAASC,2BAA2B,QAAQ,qCAAiC;AAC7E,SAASC,2BAA2B,QAAQ,qCAAiC;AAC7E,SAASC,0BAA0B,QAAQ,oCAAgC;AAC3E,SAASC,2BAA2B,QAAQ,qCAAiC;AAC7E,SAASC,oBAAoB,QAAQ,6BAAyB;AAC9D,SAASC,sBAAsB,QAAQ,+BAA2B;AAClE,SAASC,mBAAmB,QAAQ,4BAAwB;AAC5D,SAASC,qBAAqB,QAAQ,8BAA0B;AAEhE;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC;IACd,mEAAmE;IACnE,+DAA+D;IAC/DzC,wBAAwBe;IACxB;;;;;;;;;;;;;GAaC,GACDd,4BACE;QACEyC,OAAO;QACPC,SAAS,OAAOC;YACd,IAAIA,SAASC,MAAM,KAAK,GAAG,OAAO;YAClC,MAAM,EAAEC,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAC/C;YAEF,MAAM,EAAEC,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC;YAC3C,OAAOA,kBAAkB,MAAMD,yBAAyBF,QAAQ,CAAC,EAAE;QACrE;IACF,GACA,uEAAuE;IACvE,mEAAmE;IACnE,sCAAsC;IACtC;QAAEI,UAAU3C;IAAU;IAExB;;;;;;;;GAQC,GACDH,gCAAgCsB,8BAA8B;QAC5DwB,UAAU3C;IACZ;IACA;;;;;GAKC,GACDF,wBAAwBsB,4BAA4B;QAAEuB,UAAU3C;IAAU;IAC1E,wEAAwE;IACxE,2EAA2E;IAC3E,4CAA4C;IAC5CD,sBAAsBsB,0BAA0B;QAAEsB,UAAU3C;IAAU;IACtEN,uBAAuB,wBAAwBW;IAC/CX,uBAAuB,uBAAuBY;IAC9CZ,uBAAuB,uBAAuBa;IAC9Cb,uBAAuB,8BAA8Bc;IACrDd,uBAAuB,8BAA8BoB;IACrDpB,uBAAuB,gCAAgCqB;IACvD,6EAA6E;IAC7E,4EAA4E;IAC5ErB,uBAAuB,6BAA6BsB;IACpDtB,uBACE,sCACAiB;IAEFjB,uBACE,qCACAkB;IAEFlB,uBACE,sCACAmB;IAEF,wEAAwE;IACxE,0EAA0E;IAC1E,mEAAmE;IACnEnB,uBAAuB,+BAA+ByC;IACtDzC,uBAAuB,gCAAgCe;IACvDf,uBAAuB,6BAA6BuB;IACpDvB,uBAAuB,uBAAuBwB;IAC9CxB,uBAAuB,sBAAsBgC;IAC7C;;;;;;GAMC,GACDhC,uBAAuB,6BAA6B;QAClDkD,KAAKtB;IACP;IACA,yEAAyE;IACzE,0EAA0E;IAC1E5B,uBAAuB,6BAA6B;QAClDkD,KAAKrB;IACP;IACA,sEAAsE;IACtE,sEAAsE;IACtE,sCAAsC;IACtC7B,uBAAuB,2BAA2B;QAChDkD,KAAKnB;IACP;IACA,uEAAuE;IACvE,qEAAqE;IACrE/B,uBAAuB,8BAA8B;QACnDkD,KAAKpB;IACP;IACA9B,uBAAuB,uBAAuBiC;IAC9CjC,uBACE,iCACAkC;IAEFlC,uBACE,oCACAU;IAEFV,uBAAuB,8BAA8BsC;IACrDtC,uBAAuB,gCAAgCuC;IACvDvC,uBAAuB,6BAA6BwC;IACpDxC,uBACE,sCACAmC;IAEFnC,uBACE,qCACAoC;IAEFpC,uBACE,sCACAqC;IAEF,yEAAyE;IACzErC,uBAAuB,8BAA8BS;IACrD,oEAAoE;IACpEV,8BAA8BQ;IAC9B,kEAAkE;IAClE,uBAAuB;IACvBC;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerCustomFieldType,\n} from '@aglyn/aglyn/server'\n// Its own subpath, never the plugin-manager barrel: what a published page\n// does not need, it must not import.\nimport { registerPluginRouteMetadata } from '@aglyn/aglyn/plugin-manager/plugin-route-metadata'\nimport { registerPluginArtifactInventory } from '@aglyn/aglyn/plugin-manager/plugin-artifact-inventory'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { marketplaceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerMarketplaceLockdown } from './server/publisher-lockdown'\nimport { publishPluginHandler } from './server/publish-plugin'\nimport { verificationRequestHandler } from './server/verification-request'\nimport { checkoutHandler } from './server/checkout'\nimport { connectHandler } from './server/connect'\nimport { installHandler } from './server/install'\nimport { installPluginHandler } from './server/install-plugin'\nimport { listingVersionsHandler } from './server/listing-versions'\nimport { RATING_FIELD } from './model/rating-field'\nimport { installDatasetSchemaHandler } from './server/install-dataset-schema'\nimport { installEmailStarterHandler } from './server/install-email-starter'\nimport { installEmailTemplateHandler } from './server/install-email-template'\nimport { installLayoutHandler } from './server/install-layout'\nimport { installTemplateHandler } from './server/install-template'\nimport { installThemeHandler } from './server/install-theme'\nimport { previewImageHandler } from './server/preview-image'\nimport { publishHandler } from './server/publish'\nimport { marketplaceArtifactInventory } from './server/artifact-inventory'\nimport { marketplaceTaxReturnSource } from './server/tax-return-source'\nimport { marketplaceRevenueSource } from './server/revenue-source'\nimport { marketplaceAdminReports } from './server/admin-reports'\nimport { marketplaceAdminReviews } from './server/admin-reviews'\nimport { marketplaceAdminOverview } from './server/admin-overview'\nimport { marketplaceAdminTrust } from './server/admin-trust'\nimport { reportHandler } from './server/report'\nimport { reviewsHandler } from './server/reviews'\nimport { publisherProfileSaveHandler } from './server/publisher-profile-save'\nimport { publishDatasetSchemaHandler } from './server/publish-dataset-schema'\nimport { publishEmailStarterHandler } from './server/publish-email-starter'\nimport { publishEmailTemplateHandler } from './server/publish-email-template'\nimport { publishLayoutHandler } from './server/publish-layout'\nimport { publishStarterHandler } from './server/publish-starter'\nimport { publishTemplateHandler } from './server/publish-template'\nimport { publishThemeHandler } from './server/publish-theme'\nimport { updateArtifactHandler } from './server/update-artifact'\n\n/**\n * Registers the marketplace plugin's console-side API routes (AGL-396):\n * marketplace publish/install of templates and plugins, and the Stripe\n * Connect + checkout flows for paid listings.\n *\n * Upload-bodied routes register here too. The note that used to sit here —\n * that they had to stay as named console routes because the dispatcher\n * \"can't grant per-route bodyParser limits\" — was a Pages Router leftover:\n * `runLegacyHandler` reads the request through the same\n * `pluginRequestFromWeb` a named App Router route would, and imposes no\n * limit of its own. publish-plugin's 8 MB bundle has been going through the\n * dispatcher the whole time.\n */\nexport function registerMarketplaceConsoleApi(): void {\n // Server side of the rating custom field (AGL-434): validators run\n // on import/write paths even when no client loaded the plugin.\n registerCustomFieldType(RATING_FIELD)\n /*\n * What a listing link unfurls as (AGL-876, handed to the platform by\n * AGL-3080).\n *\n * The card used to be built by a hand-written console route with a server\n * layout of its own, which is what kept that route out of the generic\n * plugin route — moving it would have dropped every listing's card with\n * nothing red. The shell asks this instead, so the card survives the move\n * and no console file reads `marketplaceListings` to build a head.\n *\n * One segment and one only: `/{org}/marketplace/{listingId}`. The hub, the\n * publish page and every other address under this route answer `null`,\n * which leaves the shell's own title exactly as it was.\n */\n registerPluginRouteMetadata(\n {\n route: 'marketplace',\n resolve: async (segments) => {\n if (segments.length !== 1) return null\n const { readListingForSocialCard } = await import(\n './server/listing-social-card.server'\n )\n const { listingSocialCard } = await import('./model/listing-social-card')\n return listingSocialCard(await readListingForSocialCard(segments[0]))\n },\n },\n // Named, because this registrar is called directly by the app's server\n // loader rather than from inside a plugin `register` fn, where the\n // loader's owner marker would be set.\n { pluginId: BUNDLE_ID },\n )\n /*\n * Who claims the bytes in the artifacts bucket (AGL-3080).\n *\n * The platform's two scheduled sweeps run from `/api/admin` routes that\n * used to walk `pluginVersions` and `marketplaceListings` themselves. They\n * ask here now — and an unregistered inventory REFUSES both runs rather\n * than reporting an empty bucket, which is the whole point of the\n * contract's shape.\n */\n registerPluginArtifactInventory(marketplaceArtifactInventory, {\n pluginId: BUNDLE_ID,\n })\n /*\n * Its sales on the operator's own sales tax return (AGL-3080): the tax a\n * marketplace charge adds on the platform's own account. The staff return\n * awaits this surface before it asks, and refuses to be filed without this\n * source — the marketplace declares `taxReturnSource`.\n */\n registerTaxReturnSource(marketplaceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the commission its sales earn the operator, on the staff revenue\n // report — declared `revenueSource`, so a missing registration is named as\n // unread there rather than counted as zero.\n registerRevenueSource(marketplaceRevenueSource, { pluginId: BUNDLE_ID })\n registerPluginApiRoute('marketplace/checkout', checkoutHandler)\n registerPluginApiRoute('marketplace/connect', connectHandler)\n registerPluginApiRoute('marketplace/install', installHandler)\n registerPluginApiRoute('marketplace/install-plugin', installPluginHandler)\n registerPluginApiRoute('marketplace/install-layout', installLayoutHandler)\n registerPluginApiRoute('marketplace/install-template', installTemplateHandler)\n // A theme install DOES change the running site (AGL-1020) — it is the site's\n // appearance — so this route also owns the ways back: `revert` and `reset`.\n registerPluginApiRoute('marketplace/install-theme', installThemeHandler)\n registerPluginApiRoute(\n 'marketplace/install-dataset-schema',\n installDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-starter',\n installEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-template',\n installEmailTemplateHandler,\n )\n // Updating a copied artifact is its own route (AGL-1018), not a flag on\n // install: install writes the publisher's version, this one reconciles it\n // with a copy that has diverged and refuses to overwrite silently.\n registerPluginApiRoute('marketplace/update-artifact', updateArtifactHandler)\n registerPluginApiRoute('marketplace/listing-versions', listingVersionsHandler)\n registerPluginApiRoute('marketplace/preview-image', previewImageHandler)\n registerPluginApiRoute('marketplace/publish', publishHandler)\n registerPluginApiRoute('marketplace/report', reportHandler)\n /*\n * The staff end of that button (AGL-2310), moved out of\n * `apps/console/app/api/admin/` by AGL-3080. `web:` because it is a plain\n * fetch from this plugin's own staff page, not a plugin-request handler —\n * the same shape the AI plugin's `ai/admin/*` routes use, and for the same\n * reason: a staff route names no host, so there is no subject to resolve.\n */\n registerPluginApiRoute('marketplace/admin/reports', {\n web: marketplaceAdminReports,\n })\n // The review queue (AGL-432, moved by AGL-3080). Same shape and the same\n // reason: a staff route names no host, so there is no subject to resolve.\n registerPluginApiRoute('marketplace/admin/reviews', {\n web: marketplaceAdminReviews,\n })\n // Realm trust (AGL-420, moved by AGL-3080). Super-staff only, and the\n // SIGNATURE comes from the shell — the key is the console's and stays\n // there. See `server/admin-trust.ts`.\n registerPluginApiRoute('marketplace/admin/trust', {\n web: marketplaceAdminTrust,\n })\n // The staff overview's marketplace cards (AGL-3080): purchases and the\n // refund-reversal recovery queue. Staff-gated like the queues above.\n registerPluginApiRoute('marketplace/admin/overview', {\n web: marketplaceAdminOverview,\n })\n registerPluginApiRoute('marketplace/reviews', reviewsHandler)\n registerPluginApiRoute(\n 'marketplace/publisher-profile',\n publisherProfileSaveHandler,\n )\n registerPluginApiRoute(\n 'marketplace/verification-request',\n verificationRequestHandler,\n )\n registerPluginApiRoute('marketplace/publish-layout', publishLayoutHandler)\n registerPluginApiRoute('marketplace/publish-template', publishTemplateHandler)\n // A whole site as a site starter, picked in \"Create site\" (AGL-4049).\n registerPluginApiRoute('marketplace/publish-starter', publishStarterHandler)\n registerPluginApiRoute('marketplace/publish-theme', publishThemeHandler)\n registerPluginApiRoute(\n 'marketplace/publish-dataset-schema',\n publishDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-starter',\n publishEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-template',\n publishEmailTemplateHandler,\n )\n // Relocated console routes (AGL-418): URLs preserved via the dispatcher.\n registerPluginApiRoute('marketplace/publish-plugin', publishPluginHandler)\n // Marketplace purchases ride the platform Stripe webhook (AGL-418).\n registerBillingWebhookHandler(marketplaceBillingWebhookHandler)\n // A workspace lock reaches the publisher's payout account and its\n // listings (AGL-3365).\n registerMarketplaceLockdown()\n}\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { marketplacePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerCustomFieldType","registerPluginRouteMetadata","registerPluginArtifactInventory","registerTaxReturnSource","registerRevenueSource","BUNDLE_ID","marketplaceBillingWebhookHandler","registerMarketplaceLockdown","publishPluginHandler","verificationRequestHandler","checkoutHandler","connectHandler","installHandler","installPluginHandler","listingVersionsHandler","RATING_FIELD","installDatasetSchemaHandler","installEmailStarterHandler","installEmailTemplateHandler","installLayoutHandler","installTemplateHandler","installThemeHandler","previewImageHandler","publishHandler","marketplaceArtifactInventory","marketplaceTaxReturnSource","marketplaceRevenueSource","marketplaceAdminReports","marketplaceAdminReviews","marketplaceAdminOverview","marketplaceAdminTrust","reportHandler","reviewsHandler","publisherProfileSaveHandler","publishDatasetSchemaHandler","publishEmailStarterHandler","publishEmailTemplateHandler","publishLayoutHandler","publishStarterHandler","publishTemplateHandler","publishThemeHandler","updateArtifactHandler","registerMarketplaceConsoleApi","route","resolve","segments","length","readListingForSocialCard","listingSocialCard","pluginId","web"],"mappings":"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"}
|