@extenshi/cli 0.22.0 → 0.23.1
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/dist/auto-evidence.d.ts +59 -5
- package/dist/auto-evidence.d.ts.map +1 -1
- package/dist/auto-evidence.js +107 -7
- package/dist/auto-evidence.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +122 -24
- package/dist/cli.js.map +1 -1
- package/dist/domain.d.ts +40 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +64 -0
- package/dist/domain.js.map +1 -0
- package/dist/extension-localization.d.ts +6 -1
- package/dist/extension-localization.d.ts.map +1 -1
- package/dist/extension-localization.js +4 -0
- package/dist/extension-localization.js.map +1 -1
- package/dist/landing-page.d.ts +22 -4
- package/dist/landing-page.d.ts.map +1 -1
- package/dist/landing-page.js +14 -11
- package/dist/landing-page.js.map +1 -1
- package/dist/landing-sections.d.ts +332 -0
- package/dist/landing-sections.d.ts.map +1 -0
- package/dist/landing-sections.js +1071 -0
- package/dist/landing-sections.js.map +1 -0
- package/dist/listing.d.ts +15 -0
- package/dist/listing.d.ts.map +1 -1
- package/dist/listing.js +1 -1
- package/dist/listing.js.map +1 -1
- package/dist/page.d.ts +100 -21
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +217 -17
- package/dist/page.js.map +1 -1
- package/dist/pay-contract.d.ts +36 -12
- package/dist/pay-contract.d.ts.map +1 -1
- package/dist/pay-contract.js +24 -1
- package/dist/pay-contract.js.map +1 -1
- package/dist/pay-test-cycle.d.ts.map +1 -1
- package/dist/pay-test-cycle.js +6 -1
- package/dist/pay-test-cycle.js.map +1 -1
- package/dist/project.d.ts +30 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +140 -42
- package/dist/project.js.map +1 -1
- package/dist/scan.d.ts +8 -11
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +8 -11
- package/dist/scan.js.map +1 -1
- package/dist/screenshots-scenes.d.ts +102 -102
- package/dist/screenshots.d.ts +3 -5
- package/dist/screenshots.d.ts.map +1 -1
- package/dist/screenshots.js +7 -6
- package/dist/screenshots.js.map +1 -1
- package/dist/telemetry.d.ts +7 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +8 -0
- package/dist/telemetry.js.map +1 -1
- package/package.json +5 -5
package/dist/auto-evidence.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `--evidence` on `scan`, `review-risk`, `generate-listing
|
|
3
|
-
* turn the result the command just computed into the readiness
|
|
4
|
-
* attests, with the digests `releaseReadiness` matches against,
|
|
5
|
-
* the project bound in this directory — through the same client
|
|
6
|
-
* `extenshi evidence push` (project.ts → recordAgentEvidence).
|
|
2
|
+
* `--evidence` on `scan`, `review-risk`, `generate-listing`, `test smoke` and
|
|
3
|
+
* `screenshots`: turn the result the command just computed into the readiness
|
|
4
|
+
* evidence kind it attests, with the digests `releaseReadiness` matches against,
|
|
5
|
+
* and record it for the project bound in this directory — through the same client
|
|
6
|
+
* path as `extenshi evidence push` (project.ts → recordAgentEvidence).
|
|
7
7
|
*
|
|
8
8
|
* The digests are the contract (shared-types/project-workspace.ts
|
|
9
9
|
* `releaseReadiness`):
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* installed sha256(zip) sha256(zip) —
|
|
14
14
|
* permissions sha256(zip) hashMetadata(packaged manifest) —
|
|
15
15
|
* listing sha256(zip) sha256(listing file bytes) each locale
|
|
16
|
+
* screenshots sha256(zip) sha256(listing file bytes) each shot locale
|
|
16
17
|
*
|
|
17
18
|
* `hashMetadata(manifest)` is what `release prepare` stores as manifestDigest,
|
|
18
19
|
* and `sha256(listing file)` is what `release prepare --listing <file>` stores as
|
|
@@ -30,6 +31,12 @@
|
|
|
30
31
|
* so failing readiness on them would block releases on false
|
|
31
32
|
* positives. An advisory finding leaves the check `passed`.
|
|
32
33
|
* installed the smoke result.
|
|
34
|
+
* screenshots failed when the store's set for that locale is empty or over the
|
|
35
|
+
* store's limit (Chrome 5, Edge 6) — it cannot be submitted as shot.
|
|
36
|
+
* A locale the run cannot verify stops the run, so nothing is recorded.
|
|
37
|
+
*
|
|
38
|
+
* `screenshots` records carry their PNGs as attachments (private storage, the
|
|
39
|
+
* `evidence push --attach` upload path) — see recordScreenshotsEvidence.
|
|
33
40
|
*
|
|
34
41
|
* `permissions` and `listing` carry a `summary` (finding count, blocking count,
|
|
35
42
|
* distinct check ids) so the advisories behind a `passed` stay visible to
|
|
@@ -39,9 +46,20 @@
|
|
|
39
46
|
import { type Listing } from './listing.js';
|
|
40
47
|
import type { EvidenceRecord } from './project.js';
|
|
41
48
|
import { type ReviewFinding } from './review-checks.js';
|
|
49
|
+
import type { ScreenshotFile, ScreenshotsResult } from './screenshots.js';
|
|
42
50
|
import type { SmokeResult } from './smoke.js';
|
|
43
51
|
export type EvidenceBrowser = 'chrome' | 'edge' | 'firefox';
|
|
44
52
|
export declare const sha256Hex: (bytes: Uint8Array | string) => string;
|
|
53
|
+
/**
|
|
54
|
+
* `--evidence` is checked BEFORE the work it attests: a paid scan that cannot
|
|
55
|
+
* record its evidence afterwards would spend a credit for nothing.
|
|
56
|
+
*/
|
|
57
|
+
export declare function assertEvidenceBinding(cwd?: string): void;
|
|
58
|
+
/** Evidence binds to the exact package bytes, so it needs a package file, not an unpacked folder. */
|
|
59
|
+
export declare function evidenceArtifact(artifact: string): Promise<{
|
|
60
|
+
bytes: Buffer;
|
|
61
|
+
digest: string;
|
|
62
|
+
}>;
|
|
45
63
|
/**
|
|
46
64
|
* Which store(s) the evidence is for: the explicit list, else the browsers
|
|
47
65
|
* `extenshi package` recorded for these exact bytes (Chrome and Edge built from
|
|
@@ -90,6 +108,42 @@ export declare function generatedListingEvidence(input: {
|
|
|
90
108
|
draftPath: string;
|
|
91
109
|
browsers: EvidenceBrowser[];
|
|
92
110
|
}): Promise<EvidenceRecord[]>;
|
|
111
|
+
/**
|
|
112
|
+
* What `screenshots --evidence` needs, settled before Chromium starts: the bound
|
|
113
|
+
* project, the exact zip (it is also what gets shot), the listing revision the
|
|
114
|
+
* shots illustrate, and the stores the evidence is for — each one a store this
|
|
115
|
+
* run shoots, since `<out>/<store>/<locale>/` is that store's own set.
|
|
116
|
+
*/
|
|
117
|
+
export declare function screenshotsEvidencePlan(input: {
|
|
118
|
+
extension: string;
|
|
119
|
+
listing?: string;
|
|
120
|
+
store?: string;
|
|
121
|
+
evidenceBrowser?: string;
|
|
122
|
+
}): Promise<{
|
|
123
|
+
artifactDigest: string;
|
|
124
|
+
listingBytes: Buffer;
|
|
125
|
+
browsers: EvidenceBrowser[];
|
|
126
|
+
}>;
|
|
127
|
+
/** One `screenshots` record per store and shot locale (status rules: file header). */
|
|
128
|
+
export declare function screenshotsEvidence(input: {
|
|
129
|
+
artifactDigest: string;
|
|
130
|
+
listingBytes: Uint8Array | string;
|
|
131
|
+
browsers: EvidenceBrowser[];
|
|
132
|
+
result: Pick<ScreenshotsResult, 'files' | 'locales'>;
|
|
133
|
+
}): EvidenceRecord[];
|
|
134
|
+
/**
|
|
135
|
+
* `screenshots --evidence`: record each record with its store's PNGs for that
|
|
136
|
+
* locale attached (project.ts → uploadEvidenceAttachment, the same upload path
|
|
137
|
+
* as `evidence push --attach`).
|
|
138
|
+
*
|
|
139
|
+
* Every file passes the local checks — type, 10 MB each, at most
|
|
140
|
+
* EVIDENCE_ATTACHMENTS_MAX per record, and bytes still matching the sha256 the
|
|
141
|
+
* run wrote to screenshots.json — before the first upload. Then one locale at a
|
|
142
|
+
* time: upload, record. The server caps uploads no record references yet (100
|
|
143
|
+
* per project), so uploading every locale ahead of a single record call would
|
|
144
|
+
* fail a large run midway; a locale is at most 12 scenes × 2 sizes.
|
|
145
|
+
*/
|
|
146
|
+
export declare function recordScreenshotsEvidence(records: EvidenceRecord[], files: readonly ScreenshotFile[], cwd?: string): Promise<void>;
|
|
93
147
|
/**
|
|
94
148
|
* Record the batch for the bound project and say so on stderr (stdout stays the
|
|
95
149
|
* command's own output, e.g. --json). A queued (offline) record sets exit code 1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-evidence.d.ts","sourceRoot":"","sources":["../src/auto-evidence.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auto-evidence.d.ts","sourceRoot":"","sources":["../src/auto-evidence.ts"],"names":[],"mappings":"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"}
|
package/dist/auto-evidence.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `--evidence` on `scan`, `review-risk`, `generate-listing
|
|
3
|
-
* turn the result the command just computed into the readiness
|
|
4
|
-
* attests, with the digests `releaseReadiness` matches against,
|
|
5
|
-
* the project bound in this directory — through the same client
|
|
6
|
-
* `extenshi evidence push` (project.ts → recordAgentEvidence).
|
|
2
|
+
* `--evidence` on `scan`, `review-risk`, `generate-listing`, `test smoke` and
|
|
3
|
+
* `screenshots`: turn the result the command just computed into the readiness
|
|
4
|
+
* evidence kind it attests, with the digests `releaseReadiness` matches against,
|
|
5
|
+
* and record it for the project bound in this directory — through the same client
|
|
6
|
+
* path as `extenshi evidence push` (project.ts → recordAgentEvidence).
|
|
7
7
|
*
|
|
8
8
|
* The digests are the contract (shared-types/project-workspace.ts
|
|
9
9
|
* `releaseReadiness`):
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* installed sha256(zip) sha256(zip) —
|
|
14
14
|
* permissions sha256(zip) hashMetadata(packaged manifest) —
|
|
15
15
|
* listing sha256(zip) sha256(listing file bytes) each locale
|
|
16
|
+
* screenshots sha256(zip) sha256(listing file bytes) each shot locale
|
|
16
17
|
*
|
|
17
18
|
* `hashMetadata(manifest)` is what `release prepare` stores as manifestDigest,
|
|
18
19
|
* and `sha256(listing file)` is what `release prepare --listing <file>` stores as
|
|
@@ -30,6 +31,12 @@
|
|
|
30
31
|
* so failing readiness on them would block releases on false
|
|
31
32
|
* positives. An advisory finding leaves the check `passed`.
|
|
32
33
|
* installed the smoke result.
|
|
34
|
+
* screenshots failed when the store's set for that locale is empty or over the
|
|
35
|
+
* store's limit (Chrome 5, Edge 6) — it cannot be submitted as shot.
|
|
36
|
+
* A locale the run cannot verify stops the run, so nothing is recorded.
|
|
37
|
+
*
|
|
38
|
+
* `screenshots` records carry their PNGs as attachments (private storage, the
|
|
39
|
+
* `evidence push --attach` upload path) — see recordScreenshotsEvidence.
|
|
33
40
|
*
|
|
34
41
|
* `permissions` and `listing` carry a `summary` (finding count, blocking count,
|
|
35
42
|
* distinct check ids) so the advisories behind a `passed` stay visible to
|
|
@@ -38,7 +45,9 @@
|
|
|
38
45
|
*/
|
|
39
46
|
import { createHash } from 'node:crypto';
|
|
40
47
|
import fs from 'node:fs';
|
|
41
|
-
import {
|
|
48
|
+
import { readFile } from 'node:fs/promises';
|
|
49
|
+
import path from 'node:path';
|
|
50
|
+
import { EVIDENCE_ATTACHMENTS_MAX, hashMetadata } from '@extenshi/contracts';
|
|
42
51
|
import { InvalidInputError } from './expected-error.js';
|
|
43
52
|
import { assembleListing } from './listing.js';
|
|
44
53
|
import { packagedBrowsersFor } from './package.js';
|
|
@@ -46,8 +55,24 @@ import { summarizeCompliance, summarizeReport } from './render.js';
|
|
|
46
55
|
import { computeVerdict } from './report.js';
|
|
47
56
|
import { loadArtifact } from './review-archive.js';
|
|
48
57
|
import { runListingOnlyChecks } from './review-checks.js';
|
|
58
|
+
import { parseStores, STORE_SCREENSHOT_SPECS } from './store-assets.js';
|
|
49
59
|
const BROWSERS = ['chrome', 'edge', 'firefox'];
|
|
50
60
|
export const sha256Hex = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
61
|
+
/**
|
|
62
|
+
* `--evidence` is checked BEFORE the work it attests: a paid scan that cannot
|
|
63
|
+
* record its evidence afterwards would spend a credit for nothing.
|
|
64
|
+
*/
|
|
65
|
+
export function assertEvidenceBinding(cwd = process.cwd()) {
|
|
66
|
+
if (!fs.existsSync(path.join(cwd, '.extenshi/project.json')))
|
|
67
|
+
throw new InvalidInputError('--evidence records against the project bound in this directory. Run extenshi project bind --project <id> --repo <owner/repo> first.');
|
|
68
|
+
}
|
|
69
|
+
/** Evidence binds to the exact package bytes, so it needs a package file, not an unpacked folder. */
|
|
70
|
+
export async function evidenceArtifact(artifact) {
|
|
71
|
+
if (!fs.existsSync(artifact) || !fs.statSync(artifact).isFile())
|
|
72
|
+
throw new InvalidInputError('--evidence binds to the exact package: pass the zip (e.g. from extenshi package), not an unpacked folder.');
|
|
73
|
+
const bytes = await readFile(artifact);
|
|
74
|
+
return { bytes, digest: sha256Hex(bytes) };
|
|
75
|
+
}
|
|
51
76
|
/**
|
|
52
77
|
* Which store(s) the evidence is for: the explicit list, else the browsers
|
|
53
78
|
* `extenshi package` recorded for these exact bytes (Chrome and Edge built from
|
|
@@ -167,6 +192,80 @@ export async function generatedListingEvidence(input) {
|
|
|
167
192
|
listingFindings: runListingOnlyChecks(listing),
|
|
168
193
|
});
|
|
169
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* What `screenshots --evidence` needs, settled before Chromium starts: the bound
|
|
197
|
+
* project, the exact zip (it is also what gets shot), the listing revision the
|
|
198
|
+
* shots illustrate, and the stores the evidence is for — each one a store this
|
|
199
|
+
* run shoots, since `<out>/<store>/<locale>/` is that store's own set.
|
|
200
|
+
*/
|
|
201
|
+
export async function screenshotsEvidencePlan(input) {
|
|
202
|
+
assertEvidenceBinding();
|
|
203
|
+
const { digest } = await evidenceArtifact(input.extension);
|
|
204
|
+
const listing = input.listing;
|
|
205
|
+
if (!listing)
|
|
206
|
+
throw new InvalidInputError('--evidence binds screenshots to the listing they illustrate: pass --listing <file>, the file you give release prepare --listing.');
|
|
207
|
+
const listingBytes = await readFile(listing).catch(() => {
|
|
208
|
+
throw new InvalidInputError(`Listing file not found: ${listing}`);
|
|
209
|
+
});
|
|
210
|
+
const browsers = evidenceBrowsers(input.extension, digest, input.evidenceBrowser ?? input.store);
|
|
211
|
+
const shot = parseStores(input.store);
|
|
212
|
+
const unshot = browsers.filter((b) => !shot.includes(b));
|
|
213
|
+
if (unshot.length)
|
|
214
|
+
throw new InvalidInputError(`--evidence-browser ${unshot.join(',')}: this run shoots only ${shot.join(',')} (--store), and screenshots evidence is that store's own set.`);
|
|
215
|
+
return { artifactDigest: digest, listingBytes, browsers };
|
|
216
|
+
}
|
|
217
|
+
/** One `screenshots` record per store and shot locale (status rules: file header). */
|
|
218
|
+
export function screenshotsEvidence(input) {
|
|
219
|
+
const inputDigest = sha256Hex(input.listingBytes);
|
|
220
|
+
return input.browsers.flatMap((browser) => input.result.locales.map(({ locale }) => {
|
|
221
|
+
const count = input.result.files.filter((f) => f.store === browser && f.locale === locale).length;
|
|
222
|
+
const max = STORE_SCREENSHOT_SPECS[browser].max;
|
|
223
|
+
return {
|
|
224
|
+
kind: 'screenshots',
|
|
225
|
+
browser,
|
|
226
|
+
locale,
|
|
227
|
+
artifactDigest: input.artifactDigest,
|
|
228
|
+
inputDigest,
|
|
229
|
+
status: count && (max === null || count <= max) ? 'passed' : 'failed',
|
|
230
|
+
};
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* `screenshots --evidence`: record each record with its store's PNGs for that
|
|
235
|
+
* locale attached (project.ts → uploadEvidenceAttachment, the same upload path
|
|
236
|
+
* as `evidence push --attach`).
|
|
237
|
+
*
|
|
238
|
+
* Every file passes the local checks — type, 10 MB each, at most
|
|
239
|
+
* EVIDENCE_ATTACHMENTS_MAX per record, and bytes still matching the sha256 the
|
|
240
|
+
* run wrote to screenshots.json — before the first upload. Then one locale at a
|
|
241
|
+
* time: upload, record. The server caps uploads no record references yet (100
|
|
242
|
+
* per project), so uploading every locale ahead of a single record call would
|
|
243
|
+
* fail a large run midway; a locale is at most 12 scenes × 2 sizes.
|
|
244
|
+
*/
|
|
245
|
+
export async function recordScreenshotsEvidence(records, files, cwd = process.cwd()) {
|
|
246
|
+
const { prepareEvidenceAttachment } = await import('./project.js');
|
|
247
|
+
const prepared = new Map();
|
|
248
|
+
const attached = [];
|
|
249
|
+
for (const record of records) {
|
|
250
|
+
const own = files.filter((f) => f.store === record.browser && f.locale === record.locale);
|
|
251
|
+
if (own.length > EVIDENCE_ATTACHMENTS_MAX)
|
|
252
|
+
throw new InvalidInputError(`${record.browser}/${record.locale} has ${own.length} screenshots; an evidence record carries at most ${EVIDENCE_ATTACHMENTS_MAX}.`);
|
|
253
|
+
const attach = [];
|
|
254
|
+
for (const file of own) {
|
|
255
|
+
let ready = prepared.get(file.path);
|
|
256
|
+
if (!ready) {
|
|
257
|
+
ready = await prepareEvidenceAttachment(file.path);
|
|
258
|
+
if (ready.sha256 !== file.sha256)
|
|
259
|
+
throw new InvalidInputError(`${file.path} changed after it was shot; rerun extenshi screenshots.`);
|
|
260
|
+
prepared.set(file.path, ready);
|
|
261
|
+
}
|
|
262
|
+
attach.push(ready);
|
|
263
|
+
}
|
|
264
|
+
attached.push(attach.length ? { ...record, attach } : record);
|
|
265
|
+
}
|
|
266
|
+
for (const locale of [...new Set(attached.map((r) => r.locale))])
|
|
267
|
+
await recordAutoEvidence(attached.filter((r) => r.locale === locale), cwd);
|
|
268
|
+
}
|
|
170
269
|
/**
|
|
171
270
|
* Record the batch for the bound project and say so on stderr (stdout stays the
|
|
172
271
|
* command's own output, e.g. --json). A queued (offline) record sets exit code 1
|
|
@@ -181,7 +280,8 @@ export async function recordAutoEvidence(records, cwd = process.cwd()) {
|
|
|
181
280
|
.map((r) => {
|
|
182
281
|
const advisories = r.summary ? r.summary.findingCount - r.summary.blockingCount : 0;
|
|
183
282
|
const note = advisories ? ` (${advisories} advisory: ${r.summary?.findingIds.join(' ')})` : '';
|
|
184
|
-
|
|
283
|
+
const files = r.attach?.length ? ` +${r.attach.length} file(s)` : '';
|
|
284
|
+
return `${r.kind}${r.locale ? `:${r.locale}` : ''}/${r.browser}=${r.status}${note}${files}`;
|
|
185
285
|
})
|
|
186
286
|
.join(', ');
|
|
187
287
|
if (!result.summaries && records.some((r) => r.summary))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-evidence.js","sourceRoot":"","sources":["../src/auto-evidence.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auto-evidence.js","sourceRoot":"","sources":["../src/auto-evidence.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG"}
|
package/dist/cli.js
CHANGED
|
@@ -27,17 +27,16 @@
|
|
|
27
27
|
* re-reads the config on the first event of the run, so an answer given here is
|
|
28
28
|
* already in force for the very run that asked it.
|
|
29
29
|
*/
|
|
30
|
-
import { existsSync, statSync } from 'node:fs';
|
|
31
30
|
import { readFile } from 'node:fs/promises';
|
|
32
31
|
import { createRequire } from 'node:module';
|
|
33
32
|
import os from 'node:os';
|
|
34
|
-
import path from 'node:path';
|
|
35
33
|
import * as readline from 'node:readline/promises';
|
|
36
34
|
import { program } from 'commander';
|
|
37
35
|
import { runAmoSource } from './amo-source.js';
|
|
38
|
-
import { evidenceBrowsers, generatedListingEvidence, listingEvidence, permissionsEvidence, recordAutoEvidence, scanEvidence,
|
|
36
|
+
import { assertEvidenceBinding, evidenceArtifact, evidenceBrowsers, generatedListingEvidence, listingEvidence, permissionsEvidence, recordAutoEvidence, recordScreenshotsEvidence, scanEvidence, screenshotsEvidence, screenshotsEvidencePlan, smokeEvidence, } from './auto-evidence.js';
|
|
39
37
|
import { checkAutoUpdate } from './auto-update.js';
|
|
40
38
|
import { CONFIG_PATH, loadConfig, readTelemetryPreference, saveConfig, saveTelemetryPreference, } from './config.js';
|
|
39
|
+
import { runDomainAdd, runDomainRemove, runDomainStatus, runDomainVerify } from './domain.js';
|
|
41
40
|
import { registerEvidenceIngest } from './evidence-ingest.js';
|
|
42
41
|
import { InvalidInputError, isExpectedError } from './expected-error.js';
|
|
43
42
|
import { runGenerateListing } from './generate-listing.js';
|
|
@@ -49,7 +48,7 @@ import { runBrowserLogin } from './login-flow.js';
|
|
|
49
48
|
import { openBrowser, openLoopback, sleep } from './login-runtime.js';
|
|
50
49
|
import { runMediaUpload } from './media.js';
|
|
51
50
|
import { parsePackageBrowsers, resolvePackagedArtifact, runPackage } from './package.js';
|
|
52
|
-
import { runPageGenerate, runPagePublish, runPageRegister, runPageUnpublish } from './page.js';
|
|
51
|
+
import { runPageDraft, runPageGenerate, runPagePreview, runPagePublish, runPageRegister, runPageRollback, runPageUnpublish, runPageValidate, runPageVersions, } from './page.js';
|
|
53
52
|
import { registerPayCommands } from './pay.js';
|
|
54
53
|
import { registerPayTestCycle } from './pay-test-cycle.js';
|
|
55
54
|
import { registerProjectCommands } from './project.js';
|
|
@@ -114,21 +113,6 @@ async function runCommand(command, action) {
|
|
|
114
113
|
process.exit(1);
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
|
-
/**
|
|
118
|
-
* `--evidence` is checked BEFORE the work it attests: a paid scan that cannot
|
|
119
|
-
* record its evidence afterwards would spend a credit for nothing.
|
|
120
|
-
*/
|
|
121
|
-
function assertEvidenceBinding() {
|
|
122
|
-
if (!existsSync(path.join(process.cwd(), '.extenshi/project.json')))
|
|
123
|
-
throw new InvalidInputError('--evidence records against the project bound in this directory. Run extenshi project bind --project <id> --repo <owner/repo> first.');
|
|
124
|
-
}
|
|
125
|
-
/** Evidence binds to the exact package bytes, so it needs a package file, not an unpacked folder. */
|
|
126
|
-
async function evidenceArtifact(artifact) {
|
|
127
|
-
if (!existsSync(artifact) || !statSync(artifact).isFile())
|
|
128
|
-
throw new InvalidInputError('--evidence binds to the exact package: pass the zip (e.g. from extenshi package), not an unpacked folder.');
|
|
129
|
-
const bytes = await readFile(artifact);
|
|
130
|
-
return { bytes, digest: sha256Hex(bytes) };
|
|
131
|
-
}
|
|
132
116
|
registerProjectCommands(program);
|
|
133
117
|
registerPayTestCycle(registerPayCommands(program));
|
|
134
118
|
registerEvidenceIngest(program, runCommand);
|
|
@@ -143,7 +127,7 @@ program
|
|
|
143
127
|
.option('--output <path>', 'Path for the HTML report file (default: <artifact>-extenshi-report.html in the current directory; --format html only)')
|
|
144
128
|
.option('--no-open', 'Do not open the HTML report in the browser after generating it')
|
|
145
129
|
.option('--json', 'Shortcut for --format json (raw JSON to stdout)')
|
|
146
|
-
.option('--extension-id <id>',
|
|
130
|
+
.option('--extension-id <id>', 'Numeric catalog ID of your extension — pulls its published listing for the listing checks and enables the auto-disable diff against the last published manifest. Optional: free and paid scans both run without it.')
|
|
147
131
|
.option('--skip-preflight', 'Skip CI timeout pre-flight probe (use at your own risk)')
|
|
148
132
|
.option('--no-stream', 'Disable live progress streaming; wait for a single final JSON response')
|
|
149
133
|
.option('--api-url <url>', 'Override the scan API base URL (default: https://scan.extenshi.io)')
|
|
@@ -290,7 +274,7 @@ program
|
|
|
290
274
|
'Your build never leaves your machine: it reads the manifest and listing text locally, ' +
|
|
291
275
|
'with no API key. Pass --extension-id to also diff against your last published manifest ' +
|
|
292
276
|
'(that sends the id, not the build).')
|
|
293
|
-
.option('--extension-id <id>', 'Numeric catalog ID — enables the auto-disable diff against the last published manifest
|
|
277
|
+
.option('--extension-id <id>', 'Numeric catalog ID (the number in its catalog URL) — enables the auto-disable diff against the last published manifest')
|
|
294
278
|
.option('--catalog-url <url>', 'Override the catalog BFF base URL (default: https://bff.extenshi.io)')
|
|
295
279
|
.option('--store <store>', 'Store to diff the manifest against: chrome | firefox | edge (default: chrome). Permission sets differ per store.')
|
|
296
280
|
.option('--listing <file>', 'JSON file with your store listing text (name / shortDescription / description, optionally per locale). ' +
|
|
@@ -635,9 +619,17 @@ program
|
|
|
635
619
|
.option('--small', "Each store's smaller size: Chrome 640×400, Edge 640×480, AMO 640×400")
|
|
636
620
|
.option('--headed', 'Show the browser window (debugging scenes)')
|
|
637
621
|
.option('--json', 'Print the result as JSON')
|
|
622
|
+
.option('--evidence', 'Record `screenshots` evidence per shot locale and store for the project bound here (extenshi project bind), ' +
|
|
623
|
+
"bound to this zip and to --listing, with that store's PNGs attached (private storage). Needs a packaged zip, not a folder.")
|
|
624
|
+
.option('--listing <file>', 'With --evidence: the listing revision these screenshots illustrate — the file you give release prepare --listing')
|
|
625
|
+
.option('--evidence-browser <list>', 'Store(s) the evidence is for: chrome,edge,firefox (default: --store, else the extenshi-packages.json next to the zip); each must be shot')
|
|
638
626
|
.action(async (extension, opts) => {
|
|
639
627
|
await runCommand('screenshots', async () => {
|
|
640
|
-
|
|
628
|
+
// Settled before Chromium starts, so a run that cannot be recorded is not shot.
|
|
629
|
+
const evidence = opts.evidence ? await screenshotsEvidencePlan({ extension, ...opts }) : undefined;
|
|
630
|
+
const result = await runScreenshotsCommand(extension, opts);
|
|
631
|
+
if (evidence)
|
|
632
|
+
await recordScreenshotsEvidence(screenshotsEvidence({ ...evidence, result }), result.files);
|
|
641
633
|
});
|
|
642
634
|
});
|
|
643
635
|
program
|
|
@@ -686,8 +678,8 @@ page
|
|
|
686
678
|
});
|
|
687
679
|
page
|
|
688
680
|
.command('publish')
|
|
689
|
-
.description('Host the landing page on extenshi.io (page.extenshi.io/<code>, or
|
|
690
|
-
'domain) from the same JSON config as `page generate
|
|
681
|
+
.description('Host the landing page on extenshi.io (page.extenshi.io/<code>, or the root of your active custom ' +
|
|
682
|
+
'domain) from the same JSON config as `page generate` (v1, or schema v2 from `page draft`). Republishing keeps the URL. Also registers it ' +
|
|
691
683
|
'as the project homepage unless --no-homepage. Screenshots must be https store/Dojo images. ' +
|
|
692
684
|
'Requires an API key (extenshi login).')
|
|
693
685
|
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
@@ -700,6 +692,70 @@ page
|
|
|
700
692
|
await runPagePublish(opts);
|
|
701
693
|
});
|
|
702
694
|
});
|
|
695
|
+
page
|
|
696
|
+
.command('draft')
|
|
697
|
+
.description('Draft a full homepage (schema v2: sections, theme, SEO, locales) from the project state on extenshi.io — ' +
|
|
698
|
+
'manifest and its translations, the published page, project media, Pay offers, hosted privacy/uninstall/' +
|
|
699
|
+
'terms pages — and write it as a config for `page preview` / `page publish`. Prints where each field ' +
|
|
700
|
+
'came from and what only you can add. Writes nothing on the server. Requires an API key.')
|
|
701
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
702
|
+
.option('--out <landing.json>', 'Where to write the config', 'landing.json')
|
|
703
|
+
.option('--chrome-url <url>', 'Chrome Web Store listing URL (when the project does not know it yet)')
|
|
704
|
+
.option('--firefox-url <url>', 'Firefox Add-ons listing URL')
|
|
705
|
+
.option('--edge-url <url>', 'Edge Add-ons listing URL')
|
|
706
|
+
.action(async (opts) => {
|
|
707
|
+
await runCommand('page draft', async () => {
|
|
708
|
+
await runPageDraft(opts);
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
page
|
|
712
|
+
.command('preview')
|
|
713
|
+
.description('Validate and render a config exactly as `page publish` would (image hosts, store locales, Pay offer ' +
|
|
714
|
+
'prices, canonical URL) without publishing. Writes the page to --out; exits non-zero with every problem ' +
|
|
715
|
+
'and its fix when publish would refuse it. --screenshot saves a full-page PNG (needs Playwright + ' +
|
|
716
|
+
'Chromium, as for `extenshi screenshots`). Requires an API key.')
|
|
717
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
718
|
+
.requiredOption('--config <landing.json>', 'Landing config JSON')
|
|
719
|
+
.option('--locale <locale>', 'Which locale page to render (default: the default locale)')
|
|
720
|
+
.option('--out <path>', 'Where to write the rendered HTML', 'preview.html')
|
|
721
|
+
.option('--screenshot <png>', 'Also save a full-page screenshot')
|
|
722
|
+
.option('--logo <file>', 'Logo: .svg or .png/.jpg/.webp/.gif (≤256 KiB)')
|
|
723
|
+
.action(async (opts) => {
|
|
724
|
+
await runCommand('page preview', async () => {
|
|
725
|
+
await runPagePreview(opts);
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
page
|
|
729
|
+
.command('validate')
|
|
730
|
+
.description('Check a landing config against the shared rules offline (sections, attribution, fonts, colours, locales, ' +
|
|
731
|
+
'SEO) and print every problem with its fix. Hosted-only rules need `page preview`. No API key.')
|
|
732
|
+
.requiredOption('--config <landing.json>', 'Landing config JSON')
|
|
733
|
+
.action(async (opts) => {
|
|
734
|
+
await runCommand('page validate', async () => {
|
|
735
|
+
await runPageValidate(opts);
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
page
|
|
739
|
+
.command('versions')
|
|
740
|
+
.description('Version history of the hosted landing page (newest first; which one is live, why each exists).')
|
|
741
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
742
|
+
.action(async (opts) => {
|
|
743
|
+
await runCommand('page versions', async () => {
|
|
744
|
+
await runPageVersions(opts);
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
page
|
|
748
|
+
.command('rollback')
|
|
749
|
+
.description('Restore an earlier version of the hosted landing page. It is published as a new version (history stays ' +
|
|
750
|
+
"append-only), re-rendered with today's URL and Pay prices.")
|
|
751
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
752
|
+
.requiredOption('--version <n>', 'Version number to restore (see `extenshi page versions`)')
|
|
753
|
+
.option('--no-homepage', 'Do not register the URL as the project homepage')
|
|
754
|
+
.action(async (opts) => {
|
|
755
|
+
await runCommand('page rollback', async () => {
|
|
756
|
+
await runPageRollback(opts);
|
|
757
|
+
});
|
|
758
|
+
});
|
|
703
759
|
page
|
|
704
760
|
.command('unpublish')
|
|
705
761
|
.description('Take the hosted landing page offline (404). The URL returns on the next publish; a homepage ' +
|
|
@@ -710,6 +766,48 @@ page
|
|
|
710
766
|
await runPageUnpublish(opts);
|
|
711
767
|
});
|
|
712
768
|
});
|
|
769
|
+
const domain = program
|
|
770
|
+
.command('domain')
|
|
771
|
+
.description('Custom domain for the project homepage (served at the domain root) and every hosted page — Pro, one ' +
|
|
772
|
+
'hostname per project. Prints the exact DNS records; nothing is served until ownership (TXT) and the ' +
|
|
773
|
+
'HTTPS certificate are verified.');
|
|
774
|
+
domain
|
|
775
|
+
.command('add')
|
|
776
|
+
.description('Add www.example.com (or the apex) and print the CNAME + TXT records to set')
|
|
777
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
778
|
+
.requiredOption('--hostname <host>', 'e.g. www.example.com')
|
|
779
|
+
.action(async (opts) => {
|
|
780
|
+
await runCommand('domain add', async () => {
|
|
781
|
+
await runDomainAdd(opts);
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
domain
|
|
785
|
+
.command('status')
|
|
786
|
+
.description('Show the domain, its verification state, the DNS records and the next step')
|
|
787
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
788
|
+
.action(async (opts) => {
|
|
789
|
+
await runCommand('domain status', async () => {
|
|
790
|
+
await runDomainStatus(opts);
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
domain
|
|
794
|
+
.command('verify')
|
|
795
|
+
.description('Check ownership and the certificate now; on ACTIVE the homepage moves to the domain root and HOMEPAGE_URL follows')
|
|
796
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
797
|
+
.action(async (opts) => {
|
|
798
|
+
await runCommand('domain verify', async () => {
|
|
799
|
+
await runDomainVerify(opts);
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
domain
|
|
803
|
+
.command('remove')
|
|
804
|
+
.description('Stop serving the custom domain; the homepage returns to page.extenshi.io')
|
|
805
|
+
.requiredOption('--project <id>', 'Dojo project ID (UUID)')
|
|
806
|
+
.action(async (opts) => {
|
|
807
|
+
await runCommand('domain remove', async () => {
|
|
808
|
+
await runDomainRemove(opts);
|
|
809
|
+
});
|
|
810
|
+
});
|
|
713
811
|
/**
|
|
714
812
|
* Change or inspect the answer to the first-run telemetry question.
|
|
715
813
|
*
|