@extenshi/mcp 0.8.0 → 0.10.0

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 (52) hide show
  1. package/README.md +11 -2
  2. package/dist/bff.d.ts +33 -0
  3. package/dist/bff.d.ts.map +1 -1
  4. package/dist/bff.js +7 -0
  5. package/dist/bff.js.map +1 -1
  6. package/dist/development-guide.d.ts +121 -37
  7. package/dist/development-guide.d.ts.map +1 -1
  8. package/dist/development-guide.js +97 -12
  9. package/dist/development-guide.js.map +1 -1
  10. package/dist/icon-workflow.d.ts.map +1 -1
  11. package/dist/icon-workflow.js +15 -2
  12. package/dist/icon-workflow.js.map +1 -1
  13. package/dist/json-ld.d.ts +89 -0
  14. package/dist/json-ld.d.ts.map +1 -0
  15. package/dist/json-ld.js +118 -0
  16. package/dist/json-ld.js.map +1 -0
  17. package/dist/landing-page.d.ts +123 -0
  18. package/dist/landing-page.d.ts.map +1 -0
  19. package/dist/landing-page.js +405 -0
  20. package/dist/landing-page.js.map +1 -0
  21. package/dist/landing-workflow.d.ts +49 -0
  22. package/dist/landing-workflow.d.ts.map +1 -0
  23. package/dist/landing-workflow.js +80 -0
  24. package/dist/landing-workflow.js.map +1 -0
  25. package/dist/pay.d.ts +8 -1
  26. package/dist/pay.d.ts.map +1 -1
  27. package/dist/pay.js +9 -0
  28. package/dist/pay.js.map +1 -1
  29. package/dist/privacy-ai-outcome.d.ts +21 -0
  30. package/dist/privacy-ai-outcome.d.ts.map +1 -0
  31. package/dist/privacy-ai-outcome.js +69 -0
  32. package/dist/privacy-ai-outcome.js.map +1 -0
  33. package/dist/project-media.d.ts +29 -0
  34. package/dist/project-media.d.ts.map +1 -0
  35. package/dist/project-media.js +72 -0
  36. package/dist/project-media.js.map +1 -0
  37. package/dist/publish.d.ts +101 -0
  38. package/dist/publish.d.ts.map +1 -1
  39. package/dist/publish.js +81 -2
  40. package/dist/publish.js.map +1 -1
  41. package/dist/scan.d.ts +7 -0
  42. package/dist/scan.d.ts.map +1 -1
  43. package/dist/scan.js +26 -2
  44. package/dist/scan.js.map +1 -1
  45. package/dist/telemetry.d.ts.map +1 -1
  46. package/dist/telemetry.js +3 -0
  47. package/dist/telemetry.js.map +1 -1
  48. package/dist/tools.d.ts +1 -1
  49. package/dist/tools.d.ts.map +1 -1
  50. package/dist/tools.js +436 -15
  51. package/dist/tools.js.map +1 -1
  52. package/package.json +3 -3
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Page Generator: an extension's landing / homepage as ONE static HTML file.
3
+ *
4
+ * No JavaScript in the output — pure HTML/CSS, so it deploys anywhere
5
+ * (GitHub Pages, Netlify, S3) and trivially passes CSP. Store CTAs render
6
+ * only for the stores the developer actually filled in.
7
+ *
8
+ * Every user-supplied string is HTML-escaped, every link is scheme-clamped
9
+ * (safeHref: http(s) only; the support link may also be a single mailto:
10
+ * address) and every image source is clamped to https, a
11
+ * relative path or a raster `data:image/…;base64` URL (safeImageSrc). An
12
+ * inline SVG logo is validated (landingLogoSvgProblem) and then embedded
13
+ * through `<img src="data:image/svg+xml,…">`, where browsers never run
14
+ * scripts or fetch external resources — so even a validator miss cannot
15
+ * script the page.
16
+ *
17
+ * SINGLE SOURCE, THREE COPIES:
18
+ * shared-types/landing-page.ts (canonical — edit here; dojo re-exports it)
19
+ * tools/extenshi-mcp/src/landing-page.ts (copy for the published @extenshi/mcp)
20
+ * tools/extenshi-cli/src/landing-page.ts (copy for the published @extenshi/cli)
21
+ * The published packages cannot import workspace shared-types at runtime.
22
+ * The copies differ from this file ONLY in the json-ld import specifier
23
+ * (`./json-ld.js` there, the package specifier here — see
24
+ * module-specifiers.test.ts for why shared-types may not use relative ones).
25
+ * `landing-page-sync.test.ts` in both packages fails when a copy drifts.
26
+ * After editing, run:
27
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-mcp/src/landing-page.ts
28
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-cli/src/landing-page.ts
29
+ */
30
+ import { jsonLdFromLanding, jsonLdScriptTag } from './json-ld.js';
31
+ /** Input limits shared by the MCP tool and CLI schemas. */
32
+ export const LANDING_LIMITS = {
33
+ extensionName: 120,
34
+ tagline: 200,
35
+ description: 2000,
36
+ url: 2000,
37
+ features: 12,
38
+ featureTitle: 120,
39
+ featureDescription: 500,
40
+ screenshots: 8,
41
+ screenshotAlt: 200,
42
+ logoSvgBytes: 100_000,
43
+ logoUrl: 400_000,
44
+ };
45
+ export const DEFAULT_LANDING_FORM = {
46
+ extensionName: '',
47
+ tagline: '',
48
+ description: '',
49
+ accentColor: '#5e5ce6',
50
+ theme: 'dark',
51
+ chromeUrl: '',
52
+ firefoxUrl: '',
53
+ edgeUrl: '',
54
+ privacyPolicyUrl: '',
55
+ supportUrl: '',
56
+ features: [
57
+ { title: '', description: '' },
58
+ { title: '', description: '' },
59
+ { title: '', description: '' },
60
+ ],
61
+ };
62
+ /**
63
+ * Rebuild the editor form from a saved `page-generator` row (or the project
64
+ * name when nothing is saved). Called during render — not in an effect —
65
+ * so the live preview iframe mounts with this payload, not the empty default.
66
+ * An older row that predates `features` (or the optional fields) still yields
67
+ * a full form.
68
+ */
69
+ export function hydrateLandingForm(saved, projectName) {
70
+ if (saved?.form) {
71
+ const features = Array.isArray(saved.form.features) ? saved.form.features : DEFAULT_LANDING_FORM.features;
72
+ const { screenshots, ...rest } = saved.form;
73
+ const form = { ...DEFAULT_LANDING_FORM, ...rest, features };
74
+ if (Array.isArray(screenshots))
75
+ form.screenshots = screenshots;
76
+ return form;
77
+ }
78
+ const name = projectName?.trim();
79
+ if (name)
80
+ return { ...DEFAULT_LANDING_FORM, extensionName: name };
81
+ return { ...DEFAULT_LANDING_FORM, features: [...DEFAULT_LANDING_FORM.features] };
82
+ }
83
+ export function landingFormToInput(form, logoSvg) {
84
+ return {
85
+ extensionName: form.extensionName,
86
+ tagline: form.tagline,
87
+ description: form.description,
88
+ accentColor: form.accentColor,
89
+ theme: form.theme,
90
+ storeUrls: { chrome: form.chromeUrl, firefox: form.firefoxUrl, edge: form.edgeUrl },
91
+ features: form.features,
92
+ privacyPolicyUrl: form.privacyPolicyUrl,
93
+ supportUrl: form.supportUrl,
94
+ logoSvg: logoSvg ?? form.logoSvg ?? '',
95
+ logoUrl: form.logoUrl ?? '',
96
+ homepageUrl: form.homepageUrl ?? '',
97
+ screenshots: form.screenshots ?? [],
98
+ };
99
+ }
100
+ /** Tolerates non-strings from hand-edited JSON or an old saved row. */
101
+ function str(v) {
102
+ return typeof v === 'string' ? v.trim() : '';
103
+ }
104
+ function esc(s) {
105
+ return s
106
+ .replaceAll('&', '&amp;')
107
+ .replaceAll('<', '&lt;')
108
+ .replaceAll('>', '&gt;')
109
+ .replaceAll('"', '&quot;')
110
+ .replaceAll("'", '&#39;');
111
+ }
112
+ // HTML-escape AND scheme-clamp a user-supplied URL before it lands in an
113
+ // href="". esc() alone stops attribute-breakout but not a `javascript:`/`data:`
114
+ // scheme, so a value like `javascript:alert(1)` would survive into the
115
+ // downloaded page the developer publishes for their own users. Only http(s)
116
+ // URLs are emitted verbatim; anything else collapses to "#".
117
+ function safeHref(raw) {
118
+ const u = raw.trim();
119
+ return /^https?:\/\//i.test(u) ? esc(u) : '#';
120
+ }
121
+ // One plain address, optionally `?subject=` with a percent-encoded value.
122
+ // No `&` (a second header such as bcc/body), no raw or encoded CR/LF, no
123
+ // whitespace, and the address itself admits no `%` — so
124
+ // `mailto:a@b.c%0d%0aBcc:x` and `mailto:javascript:` are both refused.
125
+ const MAILTO = /^mailto:[A-Za-z0-9._+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+(?:\?subject=(?:[A-Za-z0-9._~-]|%(?![01][0-9a-f]|7f)[0-9a-f]{2})+)?$/i;
126
+ /** safeHref() for the support link only: http(s), or a validated mailto: address. */
127
+ function safeSupportHref(raw) {
128
+ const u = raw.trim();
129
+ return MAILTO.test(u) ? esc(u) : safeHref(u);
130
+ }
131
+ const HTTPS_URL = /^https:\/\/[^\s"'<>\\]+$/i;
132
+ const DATA_IMAGE_URL = /^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/;
133
+ // A path relative to the page: no scheme (`javascript:`, `data:`, `http:`), not
134
+ // protocol-relative (`//host`, `\\host` — browsers treat `\` as `/`), and no
135
+ // whitespace or quotes that could smuggle a second attribute.
136
+ const RELATIVE_PATH = /^(?![a-z][a-z0-9+.-]*:)(?![/\\]{2})[^\s"'<>\\]+$/i;
137
+ /** Image src clamp: https, relative path, or raster data URI; '' when unsafe. */
138
+ function safeImageSrc(raw) {
139
+ const u = str(raw);
140
+ if (!u)
141
+ return '';
142
+ if (HTTPS_URL.test(u) || RELATIVE_PATH.test(u))
143
+ return esc(u);
144
+ if (DATA_IMAGE_URL.test(u))
145
+ return u;
146
+ return '';
147
+ }
148
+ function canonicalUrl(raw) {
149
+ const u = str(raw);
150
+ return HTTPS_URL.test(u) ? u : '';
151
+ }
152
+ /** Absolute https form of an image URL (for og:image / JSON-LD), or ''. */
153
+ function absoluteImageUrl(raw, base) {
154
+ const u = str(raw);
155
+ if (HTTPS_URL.test(u))
156
+ return u;
157
+ if (!base || !RELATIVE_PATH.test(u))
158
+ return '';
159
+ try {
160
+ const resolved = new URL(u, base).href;
161
+ return HTTPS_URL.test(resolved) ? resolved : '';
162
+ }
163
+ catch {
164
+ return '';
165
+ }
166
+ }
167
+ const SVG_FORBIDDEN = [
168
+ [/<!DOCTYPE|<!ENTITY/i, 'DOCTYPE/ENTITY declarations are not allowed'],
169
+ [
170
+ /<\s*(script|foreignObject|iframe|object|embed|applet|form|input|textarea|select|button|animate|animateTransform|animateMotion|set|handler|listener)\b/i,
171
+ 'script, foreignObject, embedded documents, form controls and animation elements are not allowed',
172
+ ],
173
+ [/\son[a-z]+\s*=/i, 'event-handler attributes (on*) are not allowed'],
174
+ [/(javascript|vbscript)\s*:/i, 'script URLs are not allowed'],
175
+ [/&#/, 'numeric character references are not allowed'],
176
+ [/@import|expression\s*\(/i, 'CSS @import / expression() is not allowed'],
177
+ [
178
+ // Quote handled by alternation, not `["']?`, so backtracking cannot skip
179
+ // the quote and let `(?!#)` look at it instead of the value.
180
+ /\s(?:xlink:)?href\s*=\s*(?:"\s*|'\s*|)(?!["'#\s]|data:image\/(?:png|jpeg|gif|webp);)/i,
181
+ 'href values other than #fragments or raster data: images are not allowed',
182
+ ],
183
+ ];
184
+ /**
185
+ * Why an inline SVG logo is refused, or null when it is acceptable. A refusal
186
+ * never throws: buildLandingPage falls back to logoUrl / the monogram, and the
187
+ * MCP tool and CLI surface the reason instead of silently dropping the logo.
188
+ */
189
+ export function landingLogoSvgProblem(svg) {
190
+ const s = str(svg);
191
+ if (!s)
192
+ return 'the SVG is empty';
193
+ if (new TextEncoder().encode(s).length > LANDING_LIMITS.logoSvgBytes) {
194
+ return `the SVG exceeds ${LANDING_LIMITS.logoSvgBytes} bytes`;
195
+ }
196
+ if (!/^(?:<\?xml[^>]*\?>\s*)?(?:<!--[\s\S]*?-->\s*)*<svg[\s>]/i.test(s) || !/<\/svg>$/i.test(s)) {
197
+ return 'the logo is not a single <svg>…</svg> document';
198
+ }
199
+ for (const [pattern, reason] of SVG_FORBIDDEN)
200
+ if (pattern.test(s))
201
+ return reason;
202
+ return null;
203
+ }
204
+ const BROWSER_LABELS = {
205
+ chrome: 'Google Chrome',
206
+ firefox: 'Mozilla Firefox',
207
+ edge: 'Microsoft Edge',
208
+ };
209
+ const STORE_CTA_LABELS = {
210
+ chrome: 'Add to Chrome',
211
+ firefox: 'Get for Firefox',
212
+ edge: 'Get for Edge',
213
+ };
214
+ const DEFAULT_ACCENT = '#5e5ce6';
215
+ const HEX_COLOR = /^#[0-9a-fA-F]{3,8}$/;
216
+ /**
217
+ * Human-readable notes about input the page silently corrected (a link clamped
218
+ * to "#", an unsafe image dropped, a refused logo). Same rules as the builder,
219
+ * so agents and the CLI can report exactly what did not make it into the page.
220
+ */
221
+ export function landingPageWarnings(input) {
222
+ const out = [];
223
+ const links = [
224
+ ['chromeUrl', input.storeUrls.chrome],
225
+ ['firefoxUrl', input.storeUrls.firefox],
226
+ ['edgeUrl', input.storeUrls.edge],
227
+ ['privacyPolicyUrl', input.privacyPolicyUrl],
228
+ ];
229
+ for (const [field, value] of links) {
230
+ const v = str(value);
231
+ if (v && safeHref(v) === '#')
232
+ out.push(`${field} is not an http(s) URL; its link points to "#".`);
233
+ }
234
+ const support = str(input.supportUrl);
235
+ if (support && safeSupportHref(support) === '#') {
236
+ out.push('supportUrl is not an http(s) URL or a single mailto: address; its link points to "#".');
237
+ }
238
+ if (!Object.keys(STORE_CTA_LABELS).some((b) => str(input.storeUrls[b]))) {
239
+ out.push('No store URL is set, so the page has no install button.');
240
+ }
241
+ if (str(input.accentColor) && !HEX_COLOR.test(str(input.accentColor))) {
242
+ out.push(`accentColor is not a hex colour; ${DEFAULT_ACCENT} is used.`);
243
+ }
244
+ const homepage = canonicalUrl(input.homepageUrl);
245
+ if (str(input.homepageUrl) && !homepage) {
246
+ out.push('homepageUrl is not an https URL; canonical, og:url and JSON-LD url are omitted.');
247
+ }
248
+ const svg = str(input.logoSvg);
249
+ const svgProblem = svg ? landingLogoSvgProblem(svg) : null;
250
+ if (svgProblem)
251
+ out.push(`logoSvg was refused (${svgProblem}); the fallback logo is shown.`);
252
+ if (str(input.logoUrl) && !safeImageSrc(input.logoUrl)) {
253
+ out.push('logoUrl is not an https URL, relative path or raster data: image; it is omitted.');
254
+ }
255
+ const shots = Array.isArray(input.screenshots) ? input.screenshots : [];
256
+ let relativeShots = 0;
257
+ for (const [i, shot] of shots.slice(0, LANDING_LIMITS.screenshots).entries()) {
258
+ const url = str(shot?.url);
259
+ if (!safeImageSrc(url))
260
+ out.push(`screenshots[${i}].url is not an https URL or relative path; it is omitted.`);
261
+ else if (!HTTPS_URL.test(url) && !DATA_IMAGE_URL.test(url))
262
+ relativeShots++;
263
+ }
264
+ if (shots.length > LANDING_LIMITS.screenshots) {
265
+ out.push(`Only the first ${LANDING_LIMITS.screenshots} screenshots are used.`);
266
+ }
267
+ if (relativeShots > 0 && !homepage) {
268
+ out.push('Relative screenshot paths need an https homepageUrl to appear in og:image and JSON-LD.');
269
+ }
270
+ return out;
271
+ }
272
+ export function buildLandingPage(input) {
273
+ const rawName = str(input.extensionName) || 'My Extension';
274
+ const name = esc(rawName);
275
+ const tagline = esc(str(input.tagline));
276
+ const description = str(input.description);
277
+ const accent = HEX_COLOR.test(str(input.accentColor)) ? str(input.accentColor) : DEFAULT_ACCENT;
278
+ const dark = input.theme === 'dark';
279
+ const bg = dark ? '#0f1115' : '#ffffff';
280
+ const fg = dark ? '#e8eaf0' : '#1f2430';
281
+ const muted = dark ? '#9aa1b2' : '#5b6372';
282
+ const cardBg = dark ? '#171a21' : '#f6f7fa';
283
+ const border = dark ? '#262b36' : '#e5e8ef';
284
+ const homepage = canonicalUrl(input.homepageUrl);
285
+ const monogram = rawName.charAt(0).toUpperCase() || 'E';
286
+ const svg = str(input.logoSvg);
287
+ const logoSrc = svg && !landingLogoSvgProblem(svg)
288
+ ? `data:image/svg+xml,${encodeURIComponent(svg)}`
289
+ : safeImageSrc(input.logoUrl);
290
+ const logo = logoSrc
291
+ ? `<div class="logo"><img src="${logoSrc}" alt="${name} logo" width="64" height="64" /></div>`
292
+ : `<div class="logo monogram" aria-hidden="true">${esc(monogram)}</div>`;
293
+ const ctas = Object.keys(STORE_CTA_LABELS)
294
+ .filter((b) => str(input.storeUrls[b]))
295
+ .map((b) => `<a class="cta${b === 'chrome' ? ' primary' : ''}" href="${safeHref(str(input.storeUrls[b]))}" rel="noopener">${STORE_CTA_LABELS[b]}<span class="cta-sub">${esc(BROWSER_LABELS[b])}</span></a>`)
296
+ .join('\n\t\t\t');
297
+ const featureList = Array.isArray(input.features) ? input.features : [];
298
+ const features = featureList
299
+ .filter((f) => str(f?.title))
300
+ .map((f) => `<div class="feature">
301
+ <h3>${esc(str(f.title))}</h3>
302
+ <p>${esc(str(f.description))}</p>
303
+ </div>`)
304
+ .join('\n\t\t\t');
305
+ const shots = (Array.isArray(input.screenshots) ? input.screenshots : [])
306
+ .slice(0, LANDING_LIMITS.screenshots)
307
+ .map((shot, i) => ({
308
+ url: str(shot?.url),
309
+ src: safeImageSrc(shot?.url),
310
+ alt: str(shot?.alt).slice(0, LANDING_LIMITS.screenshotAlt) || `${rawName} screenshot ${i + 1}`,
311
+ }))
312
+ .filter((shot) => shot.src);
313
+ const screenshots = shots
314
+ .map((shot) => `<figure class="shot"><img src="${shot.src}" alt="${esc(shot.alt)}" loading="lazy" /></figure>`)
315
+ .join('\n\t\t\t');
316
+ const absoluteShots = shots.map((shot) => absoluteImageUrl(shot.url, homepage)).filter(Boolean);
317
+ const footerLinks = [];
318
+ if (str(input.privacyPolicyUrl)) {
319
+ footerLinks.push(`<a href="${safeHref(str(input.privacyPolicyUrl))}">Privacy policy</a>`);
320
+ }
321
+ if (str(input.supportUrl)) {
322
+ footerLinks.push(`<a href="${safeSupportHref(str(input.supportUrl))}">Support</a>`);
323
+ }
324
+ const jsonLd = jsonLdScriptTag(jsonLdFromLanding({
325
+ extensionName: rawName,
326
+ tagline: str(input.tagline),
327
+ description,
328
+ storeUrls: input.storeUrls,
329
+ features: featureList
330
+ .filter((f) => str(f?.title))
331
+ .map((f) => ({ title: str(f.title), description: str(f.description) })),
332
+ privacyPolicyUrl: str(input.privacyPolicyUrl),
333
+ homepageUrl: homepage || undefined,
334
+ screenshots: absoluteShots,
335
+ }));
336
+ const metaDescription = esc(description || str(input.tagline));
337
+ const ogImage = absoluteShots[0] ?? '';
338
+ const head = [
339
+ `<title>${name}${tagline ? ` — ${tagline}` : ''}</title>`,
340
+ `<meta name="description" content="${metaDescription}" />`,
341
+ homepage ? `<link rel="canonical" href="${esc(homepage)}" />` : '',
342
+ '<meta property="og:type" content="website" />',
343
+ `<meta property="og:title" content="${name}" />`,
344
+ metaDescription ? `<meta property="og:description" content="${metaDescription}" />` : '',
345
+ homepage ? `<meta property="og:url" content="${esc(homepage)}" />` : '',
346
+ ogImage ? `<meta property="og:image" content="${esc(ogImage)}" />` : '',
347
+ `<meta name="twitter:card" content="${ogImage ? 'summary_large_image' : 'summary'}" />`,
348
+ jsonLd,
349
+ ]
350
+ .filter(Boolean)
351
+ .join('\n');
352
+ return `<!doctype html>
353
+ <html lang="en">
354
+ <head>
355
+ <meta charset="utf-8" />
356
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
357
+ ${head}
358
+ <style>
359
+ * { box-sizing: border-box; margin: 0; padding: 0; }
360
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: ${bg}; color: ${fg}; line-height: 1.6; }
361
+ .wrap { max-width: 880px; margin: 0 auto; padding: 0 24px; }
362
+ header { padding: 88px 0 56px; text-align: center; }
363
+ .logo { width: 88px; height: 88px; margin: 0 auto 28px; border-radius: 22px; display: flex; align-items: center; justify-content: center; background: ${cardBg}; border: 1px solid ${border}; overflow: hidden; }
364
+ .logo img { width: 64px; height: 64px; object-fit: contain; }
365
+ .logo.monogram { font-size: 2.4rem; font-weight: 700; color: ${accent}; }
366
+ h1 { font-size: 2.6rem; letter-spacing: -0.02em; line-height: 1.15; }
367
+ .tagline { margin-top: 14px; font-size: 1.25rem; color: ${muted}; }
368
+ .ctas { margin-top: 36px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
369
+ .cta { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; padding: 12px 26px; border-radius: 12px; border: 1px solid ${border}; background: ${cardBg}; color: ${fg}; text-decoration: none; font-weight: 600; transition: transform 0.12s ease; }
370
+ .cta:hover { transform: translateY(-2px); }
371
+ .cta.primary { background: ${accent}; border-color: ${accent}; color: #fff; }
372
+ .cta-sub { font-size: 0.72rem; font-weight: 400; opacity: 0.75; }
373
+ .about { padding: 8px 0 24px; text-align: center; }
374
+ .about p { max-width: 640px; margin: 0 auto; color: ${muted}; }
375
+ .shots { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; padding: 24px 0 8px; }
376
+ .shot img { display: block; width: 100%; height: auto; border-radius: 12px; border: 1px solid ${border}; }
377
+ .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; padding: 40px 0 64px; }
378
+ .feature { background: ${cardBg}; border: 1px solid ${border}; border-radius: 14px; padding: 22px; }
379
+ .feature h3 { font-size: 1.02rem; margin-bottom: 8px; }
380
+ .feature p { font-size: 0.92rem; color: ${muted}; }
381
+ footer { border-top: 1px solid ${border}; padding: 28px 0 48px; text-align: center; font-size: 0.85rem; color: ${muted}; }
382
+ footer a { color: ${muted}; margin: 0 10px; }
383
+ </style>
384
+ </head>
385
+ <body>
386
+ <div class="wrap">
387
+ <header>
388
+ ${logo}
389
+ <h1>${name}</h1>
390
+ ${tagline ? `<p class="tagline">${tagline}</p>` : ''}
391
+ ${ctas ? `<div class="ctas">\n\t\t\t${ctas}\n\t\t\t</div>` : ''}
392
+ </header>
393
+ ${description ? `<section class="about"><p>${esc(description)}</p></section>` : ''}
394
+ ${screenshots ? `<section class="shots">\n\t\t\t${screenshots}\n\t\t</section>` : ''}
395
+ ${features ? `<section class="features">\n\t\t\t${features}\n\t\t</section>` : ''}
396
+ <footer>
397
+ ${footerLinks.join('\n\t\t\t')}
398
+ <div>© ${name}</div>
399
+ </footer>
400
+ </div>
401
+ </body>
402
+ </html>
403
+ `;
404
+ }
405
+ //# sourceMappingURL=landing-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-page.js","sourceRoot":"","sources":["../src/landing-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Body of the free `generate_landing_page` MCP tool.
3
+ *
4
+ * Pure function of its arguments — no API key, no network, no credits — so it
5
+ * is registered under the `docs` capability and works on both the local stdio
6
+ * server and the hosted connector. The HTML comes from ./landing-page.ts, a
7
+ * synced copy of shared-types/landing-page.ts: the page an agent generates here
8
+ * is byte-for-byte what the cabinet Page generator downloads for the same form.
9
+ *
10
+ * Extenshi does not host the page. The returned `nextSteps` describe hosting it
11
+ * on any HTTPS origin and registering the URL with `upsert_hosted_page`, which
12
+ * is what feeds HOMEPAGE_URL in the generated integration config.
13
+ */
14
+ import { type LandingForm } from './landing-page.js';
15
+ export interface LandingPageArgs {
16
+ extensionName: string;
17
+ tagline?: string;
18
+ description?: string;
19
+ accentColor?: string;
20
+ theme?: 'light' | 'dark';
21
+ chromeUrl?: string;
22
+ firefoxUrl?: string;
23
+ edgeUrl?: string;
24
+ privacyPolicyUrl?: string;
25
+ supportUrl?: string;
26
+ homepageUrl?: string;
27
+ features?: {
28
+ title: string;
29
+ description?: string;
30
+ }[];
31
+ screenshots?: {
32
+ url: string;
33
+ alt?: string;
34
+ }[];
35
+ logoSvg?: string;
36
+ logoUrl?: string;
37
+ }
38
+ export interface GeneratedLandingPage {
39
+ html: string;
40
+ bytes: number;
41
+ warnings: string[];
42
+ nextSteps: string[];
43
+ }
44
+ export declare function landingFormFromArgs(args: LandingPageArgs): LandingForm;
45
+ export declare function landingNextSteps(homepageUrl?: string): string[];
46
+ export declare function renderGenerateLandingPage(args: LandingPageArgs): GeneratedLandingPage;
47
+ /** Follow-ups after publish_landing_page, from the fields the BFF returned. */
48
+ export declare function hostedLandingNextSteps(result: Record<string, unknown>): string[];
49
+ //# sourceMappingURL=landing-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-workflow.d.ts","sourceRoot":"","sources":["../src/landing-workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAGN,KAAK,WAAW,EAIhB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,eAAe;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACpD,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAsBtE;AAED,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,eAAe,GAAG,oBAAoB,CAWrF;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAehF"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Body of the free `generate_landing_page` MCP tool.
3
+ *
4
+ * Pure function of its arguments — no API key, no network, no credits — so it
5
+ * is registered under the `docs` capability and works on both the local stdio
6
+ * server and the hosted connector. The HTML comes from ./landing-page.ts, a
7
+ * synced copy of shared-types/landing-page.ts: the page an agent generates here
8
+ * is byte-for-byte what the cabinet Page generator downloads for the same form.
9
+ *
10
+ * Extenshi does not host the page. The returned `nextSteps` describe hosting it
11
+ * on any HTTPS origin and registering the URL with `upsert_hosted_page`, which
12
+ * is what feeds HOMEPAGE_URL in the generated integration config.
13
+ */
14
+ import { buildLandingPage, DEFAULT_LANDING_FORM, landingFormToInput, landingPageWarnings, } from './landing-page.js';
15
+ export function landingFormFromArgs(args) {
16
+ const form = {
17
+ ...DEFAULT_LANDING_FORM,
18
+ extensionName: args.extensionName,
19
+ tagline: args.tagline ?? '',
20
+ description: args.description ?? '',
21
+ accentColor: args.accentColor ?? DEFAULT_LANDING_FORM.accentColor,
22
+ theme: args.theme ?? DEFAULT_LANDING_FORM.theme,
23
+ chromeUrl: args.chromeUrl ?? '',
24
+ firefoxUrl: args.firefoxUrl ?? '',
25
+ edgeUrl: args.edgeUrl ?? '',
26
+ privacyPolicyUrl: args.privacyPolicyUrl ?? '',
27
+ supportUrl: args.supportUrl ?? '',
28
+ features: (args.features ?? []).map((f) => ({ title: f.title, description: f.description ?? '' })),
29
+ };
30
+ if (args.homepageUrl)
31
+ form.homepageUrl = args.homepageUrl;
32
+ if (args.logoUrl)
33
+ form.logoUrl = args.logoUrl;
34
+ if (args.logoSvg)
35
+ form.logoSvg = args.logoSvg;
36
+ if (args.screenshots?.length) {
37
+ form.screenshots = args.screenshots.map((s) => ({ url: s.url, alt: s.alt ?? '' }));
38
+ }
39
+ return form;
40
+ }
41
+ export function landingNextSteps(homepageUrl) {
42
+ return [
43
+ 'Save `html` verbatim as index.html. Put any relative screenshot or logo paths next to it at the same relative locations.',
44
+ 'Host the file on a public HTTPS origin — for example GitHub Pages (commit index.html to the repository, then Settings → Pages → deploy from the branch and folder), Cloudflare Pages, Netlify or any static host. The page has no JavaScript, so it needs no build step or CSP changes.',
45
+ homepageUrl
46
+ ? `Confirm the page loads at ${homepageUrl} (the canonical/og:url tags already point there).`
47
+ : 'Once the final URL is known, regenerate with homepageUrl set to it so the canonical, og:url and JSON-LD url tags are filled in, and re-upload.',
48
+ 'Register the URL on the project: upsert_hosted_page {projectId, kind: "homepage", url} (needs identity and hosted.write; the server fetches the public page and hashes it, so it has to be publicly reachable). CLI equivalent: npx @extenshi/cli@latest page register --project <id> --url <https-url>.',
49
+ 'Re-read get_project_state and write integration.file verbatim to integration.path — the regenerated config carries the new HOMEPAGE_URL.',
50
+ 'After later edits to the hosted page, verify_hosted_artifact {projectId, kind: "homepage"} reports whether the live page still matches the registered hash.',
51
+ ];
52
+ }
53
+ export function renderGenerateLandingPage(args) {
54
+ const input = landingFormToInput(landingFormFromArgs(args));
55
+ const html = buildLandingPage(input);
56
+ return {
57
+ html,
58
+ bytes: new TextEncoder().encode(html).length,
59
+ warnings: landingPageWarnings(input),
60
+ nextSteps: landingNextSteps(/^https:\/\/\S+$/i.test(input.homepageUrl ?? '') ? input.homepageUrl : undefined),
61
+ };
62
+ }
63
+ /** Follow-ups after publish_landing_page, from the fields the BFF returned. */
64
+ export function hostedLandingNextSteps(result) {
65
+ const homepage = (result.homepage ?? {});
66
+ const steps = [
67
+ `The page is live at ${String(result.url)}; the same URL keeps serving every later version.`,
68
+ homepage.registered
69
+ ? 'It is now the project homepage. Re-read get_project_state and write integration.file verbatim to integration.path so HOMEPAGE_URL uses it.'
70
+ : 'The homepage registration was left unchanged (registerAsHomepage: false).',
71
+ 'verify_hosted_artifact {projectId, kind: "homepage"} confirms the public URL serves the published bytes (the hash is contentHash).',
72
+ ];
73
+ if (homepage.previousUrl)
74
+ steps.push(`This replaced the previously registered homepage ${homepage.previousUrl}.`);
75
+ const warnings = Array.isArray(result.warnings) ? result.warnings : [];
76
+ if (warnings.length)
77
+ steps.push('Review warnings: those values were clamped or dropped in the rendered page.');
78
+ return steps;
79
+ }
80
+ //# sourceMappingURL=landing-workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-workflow.js","sourceRoot":"","sources":["../src/landing-workflow.ts"],"names":[],"mappings":"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"}
package/dist/pay.d.ts CHANGED
@@ -38,6 +38,13 @@ export declare const paySchemas: {
38
38
  }, {
39
39
  appId: string;
40
40
  }>;
41
+ readonly getPayPaymentEvidence: z.ZodObject<{
42
+ appId: z.ZodString;
43
+ }, "strict", z.ZodTypeAny, {
44
+ appId: string;
45
+ }, {
46
+ appId: string;
47
+ }>;
41
48
  readonly linkPayApp: z.ZodObject<{
42
49
  appId: z.ZodString;
43
50
  } & {
@@ -208,7 +215,7 @@ export type PayMethod = keyof typeof paySchemas;
208
215
  export type PayBff = {
209
216
  [M in PayMethod]: (input: z.infer<(typeof paySchemas)[M]>) => Promise<unknown>;
210
217
  };
211
- export declare const PAY_OPERATIONS: readonly [readonly ["listPayApps", "list_pay_apps", "list", "payApp.list", false, "List your independent Pay applications. No development project required. Paginated: nextCursor is set while more results exist."], readonly ["createPayApp", "create_pay_app", "create", "payApp.create", true, "Create an independent Pay application; linking a development project is optional. Not idempotent: each call creates a new application, including a call repeated after a timeout."], readonly ["getPayApp", "get_pay_app", "get", "payApp.get", false, "Read your Pay application and optional project link."], readonly ["getPayReadiness", "get_pay_readiness", "readiness", "payApp.readiness", false, "Check current checkout and launch prerequisites. A passing checkout check does not prove a live external purchase or SDK publication."], readonly ["linkPayApp", "link_pay_app", "link", "payApp.link", true, "Link your Pay application to your development project. Existing purchases remain attached to the Pay application."], readonly ["unlinkPayApp", "unlink_pay_app", "unlink", "payApp.unlink", true, "Remove the optional development-project link without deleting Pay data."], readonly ["archivePayApp", "archive_pay_app", "archive", "payApp.archive", true, "Archive your application and stop new checkout. Payment records and existing entitlements are preserved."], readonly ["exportPayData", "export_pay_data", "export", "payApp.export", false, "Export one page of one resource (offers, payments, subscriptions, entitlements or customers). nextCursor is null on the last page. The output contains sensitive customer and payment data."], readonly ["getPaySeller", "get_pay_seller", "seller", "paySeller.get", false, "Read seller connection, public profile, offers, the publishable SDK key and the public entitlement verification key. Those two keys are the ones meant to be embedded in extension code; secret keys are not part of the response. Agreement signing and KYC take place in the browser."], readonly ["connectPaySeller", "connect_pay_seller", "connect", "paySeller.connect", true, "Start Stripe Connect onboarding and return a browser action URL. KYC and legal acceptance are completed by the author at that URL; this tool does not perform them."], readonly ["refreshPaySeller", "refresh_pay_seller", "refresh", "paySeller.refreshStatus", true, "Refresh current payment-provider onboarding status. This does not complete KYC or accept agreements."], readonly ["setPaySellerProfile", "set_pay_seller_profile", "profile", "paySeller.setPublicProfile", true, "Save the public seller profile: display name, support URL or email, and terms URL. The values are stored as provided and are publicly visible."], readonly ["upsertPayOffer", "upsert_pay_offer", "offer-upsert", "paySeller.upsertOffer", true, "Create or update an offer keyed by a stable SKU. Price is in minor currency units. Subscriptions keep the given billing interval; one-time and lifetime offers store no interval. Price and features are stored as provided."], readonly ["archivePayOffer", "archive_pay_offer", "offer-archive", "paySeller.archiveOffer", true, "Stop offering a SKU for new checkout; historical purchases are preserved."], readonly ["setPayEnabled", "set_pay_enabled", "enable", "paySeller.setEnabled", true, "Enable or disable new payments for the application; requires a connected payment provider. Enabling re-reads the seller status from the provider (charges and payouts). It does not verify the public profile, agreement or offer sync: buyers can check out only when every readiness check reported by get_pay_readiness passes. Enabling is a live commerce change."], readonly ["rotatePayKey", "rotate_pay_key", "rotate-key", "paySeller.rotatePublishableKey", true, "Generate a new publishable SDK key. Not idempotent: each call issues another key. Prior keys remain accepted for installed extension builds; this does not revoke any secret."]];
218
+ export declare const PAY_OPERATIONS: readonly [readonly ["listPayApps", "list_pay_apps", "list", "payApp.list", false, "List your independent Pay applications. No development project required. Paginated: nextCursor is set while more results exist."], readonly ["createPayApp", "create_pay_app", "create", "payApp.create", true, "Create an independent Pay application; linking a development project is optional. Not idempotent: each call creates a new application, including a call repeated after a timeout."], readonly ["getPayApp", "get_pay_app", "get", "payApp.get", false, "Read your Pay application and optional project link."], readonly ["getPayReadiness", "get_pay_readiness", "readiness", "payApp.readiness", false, "Check current checkout and launch prerequisites. A passing checkout check does not prove a live external purchase or SDK publication."], readonly ["getPayPaymentEvidence", "get_pay_payment_evidence", "payment-evidence", "payApp.paymentEvidence", false, "Read what Extenshi's own payment ledger proves about this application's payment path, per mode: checkout completed, license issued, an installation received the signed license, restored on a second installation, refund revoked. Derived from provider-signed webhooks, not from any report; opaque IDs and timestamps only, no buyer data. Only a live-mode purchase can satisfy a release's payment requirement; test-mode purchases are listed without satisfying it."], readonly ["linkPayApp", "link_pay_app", "link", "payApp.link", true, "Link your Pay application to your development project. Existing purchases remain attached to the Pay application."], readonly ["unlinkPayApp", "unlink_pay_app", "unlink", "payApp.unlink", true, "Remove the optional development-project link without deleting Pay data."], readonly ["archivePayApp", "archive_pay_app", "archive", "payApp.archive", true, "Archive your application and stop new checkout. Payment records and existing entitlements are preserved."], readonly ["exportPayData", "export_pay_data", "export", "payApp.export", false, "Export one page of one resource (offers, payments, subscriptions, entitlements or customers). nextCursor is null on the last page. The output contains sensitive customer and payment data."], readonly ["getPaySeller", "get_pay_seller", "seller", "paySeller.get", false, "Read seller connection, public profile, offers, the publishable SDK key and the public entitlement verification key. Those two keys are the ones meant to be embedded in extension code; secret keys are not part of the response. Agreement signing and KYC take place in the browser."], readonly ["connectPaySeller", "connect_pay_seller", "connect", "paySeller.connect", true, "Start Stripe Connect onboarding and return a browser action URL. KYC and legal acceptance are completed by the author at that URL; this tool does not perform them."], readonly ["refreshPaySeller", "refresh_pay_seller", "refresh", "paySeller.refreshStatus", true, "Refresh current payment-provider onboarding status. This does not complete KYC or accept agreements."], readonly ["setPaySellerProfile", "set_pay_seller_profile", "profile", "paySeller.setPublicProfile", true, "Save the public seller profile: display name, support URL or email, and terms URL. The values are stored as provided and are publicly visible."], readonly ["upsertPayOffer", "upsert_pay_offer", "offer-upsert", "paySeller.upsertOffer", true, "Create or update an offer keyed by a stable SKU. Price is in minor currency units. Subscriptions keep the given billing interval; one-time and lifetime offers store no interval. Price and features are stored as provided."], readonly ["archivePayOffer", "archive_pay_offer", "offer-archive", "paySeller.archiveOffer", true, "Stop offering a SKU for new checkout; historical purchases are preserved."], readonly ["setPayEnabled", "set_pay_enabled", "enable", "paySeller.setEnabled", true, "Enable or disable new payments for the application; requires a connected payment provider. Enabling re-reads the seller status from the provider (charges and payouts). It does not verify the public profile, agreement or offer sync: buyers can check out only when every readiness check reported by get_pay_readiness passes. Enabling is a live commerce change."], readonly ["rotatePayKey", "rotate_pay_key", "rotate-key", "paySeller.rotatePublishableKey", true, "Generate a new publishable SDK key. Not idempotent: each call issues another key. Prior keys remain accepted for installed extension builds; this does not revoke any secret."]];
212
219
  /** The legacy seller API uses projectId as the payment namespace. Never substitute a linked project ID. */
213
220
  export declare function payWireInput(method: PayMethod, input: Record<string, unknown>): Record<string, unknown>;
214
221
  //# sourceMappingURL=pay.d.ts.map
package/dist/pay.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pay.d.ts","sourceRoot":"","sources":["../src/pay.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAavB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDb,CAAA;AACV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,UAAU,CAAA;AAC/C,MAAM,MAAM,MAAM,GAAG;KAAG,CAAC,IAAI,SAAS,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;CAAE,CAAA;AACvG,eAAO,MAAM,cAAc,m1HAiIjB,CAAA;AAEV,2GAA2G;AAC3G,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIvG"}
1
+ {"version":3,"file":"pay.d.ts","sourceRoot":"","sources":["../src/pay.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAavB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDb,CAAA;AACV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,UAAU,CAAA;AAC/C,MAAM,MAAM,MAAM,GAAG;KAAG,CAAC,IAAI,SAAS,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;CAAE,CAAA;AACvG,eAAO,MAAM,cAAc,u5IAyIjB,CAAA;AAEV,2GAA2G;AAC3G,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIvG"}
package/dist/pay.js CHANGED
@@ -24,6 +24,7 @@ export const paySchemas = {
24
24
  .strict(),
25
25
  getPayApp: app,
26
26
  getPayReadiness: app,
27
+ getPayPaymentEvidence: app,
27
28
  linkPayApp: app.extend({ projectId: z.string().uuid() }),
28
29
  unlinkPayApp: app,
29
30
  archivePayApp: app,
@@ -95,6 +96,14 @@ export const PAY_OPERATIONS = [
95
96
  false,
96
97
  'Check current checkout and launch prerequisites. A passing checkout check does not prove a live external purchase or SDK publication.',
97
98
  ],
99
+ [
100
+ 'getPayPaymentEvidence',
101
+ 'get_pay_payment_evidence',
102
+ 'payment-evidence',
103
+ 'payApp.paymentEvidence',
104
+ false,
105
+ "Read what Extenshi's own payment ledger proves about this application's payment path, per mode: checkout completed, license issued, an installation received the signed license, restored on a second installation, refund revoked. Derived from provider-signed webhooks, not from any report; opaque IDs and timestamps only, no buyer data. Only a live-mode purchase can satisfy a release's payment requirement; test-mode purchases are listed without satisfying it.",
106
+ ],
98
107
  [
99
108
  'linkPayApp',
100
109
  'link_pay_app',