@extenshi/cli 0.21.0 → 0.22.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.
- package/README.md +4 -0
- package/dist/amo-source-detect.d.ts +18 -0
- package/dist/amo-source-detect.d.ts.map +1 -0
- package/dist/amo-source-detect.js +41 -0
- package/dist/amo-source-detect.js.map +1 -0
- package/dist/amo-source.d.ts +41 -0
- package/dist/amo-source.d.ts.map +1 -0
- package/dist/amo-source.js +240 -0
- package/dist/amo-source.js.map +1 -0
- package/dist/amowebstore-md.d.ts +38 -0
- package/dist/amowebstore-md.d.ts.map +1 -0
- package/dist/amowebstore-md.js +118 -0
- package/dist/amowebstore-md.js.map +1 -0
- package/dist/auto-evidence.d.ts +100 -0
- package/dist/auto-evidence.d.ts.map +1 -0
- package/dist/auto-evidence.js +197 -0
- package/dist/auto-evidence.js.map +1 -0
- package/dist/cli.js +265 -8
- package/dist/cli.js.map +1 -1
- package/dist/edgewebstore-md.d.ts +26 -0
- package/dist/edgewebstore-md.d.ts.map +1 -0
- package/dist/edgewebstore-md.js +95 -0
- package/dist/edgewebstore-md.js.map +1 -0
- package/dist/evidence-ingest.d.ts +60 -0
- package/dist/evidence-ingest.d.ts.map +1 -0
- package/dist/evidence-ingest.js +141 -0
- package/dist/evidence-ingest.js.map +1 -0
- package/dist/firefox-rdp.d.ts +55 -0
- package/dist/firefox-rdp.d.ts.map +1 -0
- package/dist/firefox-rdp.js +203 -0
- package/dist/firefox-rdp.js.map +1 -0
- package/dist/gecko-id.d.ts +55 -0
- package/dist/gecko-id.d.ts.map +1 -0
- package/dist/gecko-id.js +132 -0
- package/dist/gecko-id.js.map +1 -0
- package/dist/generate-listing.d.ts +19 -8
- package/dist/generate-listing.d.ts.map +1 -1
- package/dist/generate-listing.js +66 -18
- package/dist/generate-listing.js.map +1 -1
- package/dist/icon.d.ts +18 -0
- package/dist/icon.d.ts.map +1 -1
- package/dist/icon.js +29 -20
- package/dist/icon.js.map +1 -1
- package/dist/media.d.ts +42 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +96 -0
- package/dist/media.js.map +1 -0
- package/dist/package.d.ts +163 -0
- package/dist/package.d.ts.map +1 -0
- package/dist/package.js +500 -0
- package/dist/package.js.map +1 -0
- package/dist/page.d.ts +10 -0
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +32 -2
- package/dist/page.js.map +1 -1
- package/dist/pay-contract.d.ts +10 -3
- package/dist/pay-contract.d.ts.map +1 -1
- package/dist/pay-contract.js +9 -0
- package/dist/pay-contract.js.map +1 -1
- package/dist/pay-test-cycle.d.ts +40 -0
- package/dist/pay-test-cycle.d.ts.map +1 -0
- package/dist/pay-test-cycle.js +207 -0
- package/dist/pay-test-cycle.js.map +1 -0
- package/dist/pay.d.ts +1 -1
- package/dist/pay.d.ts.map +1 -1
- package/dist/pay.js +1 -0
- package/dist/pay.js.map +1 -1
- package/dist/project.d.ts +39 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +231 -20
- package/dist/project.js.map +1 -1
- package/dist/publish.d.ts +33 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +113 -2
- package/dist/publish.js.map +1 -1
- package/dist/review-checks.d.ts +13 -0
- package/dist/review-checks.d.ts.map +1 -1
- package/dist/review-checks.js.map +1 -1
- package/dist/review-risk.d.ts +10 -1
- package/dist/review-risk.d.ts.map +1 -1
- package/dist/review-risk.js +1 -0
- package/dist/review-risk.js.map +1 -1
- package/dist/scan.d.ts +3 -2
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +4 -2
- package/dist/scan.js.map +1 -1
- package/dist/screenshots-scenes.d.ts +1383 -0
- package/dist/screenshots-scenes.d.ts.map +1 -0
- package/dist/screenshots-scenes.js +276 -0
- package/dist/screenshots-scenes.js.map +1 -0
- package/dist/screenshots.d.ts +145 -0
- package/dist/screenshots.d.ts.map +1 -0
- package/dist/screenshots.js +557 -0
- package/dist/screenshots.js.map +1 -0
- package/dist/smoke.d.ts +81 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +491 -0
- package/dist/smoke.js.map +1 -0
- package/dist/store-assets.d.ts +139 -0
- package/dist/store-assets.d.ts.map +1 -0
- package/dist/store-assets.js +582 -0
- package/dist/store-assets.js.map +1 -0
- package/dist/zip.d.ts +57 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +134 -0
- package/dist/zip.js.map +1 -0
- package/package.json +4 -3
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Firefox Remote Debugging Protocol client — just enough to install a
|
|
3
|
+
* package as a TEMPORARY add-on and watch it, the way `web-ext run` and
|
|
4
|
+
* about:debugging do. No dependency: RDP is length-prefixed JSON over TCP
|
|
5
|
+
* (`<byteLength>:<json>`), and every request is answered by one packet `from`
|
|
6
|
+
* the actor it was sent `to`.
|
|
7
|
+
*
|
|
8
|
+
* Why RDP and not Playwright/Marionette: Playwright's Firefox cannot install
|
|
9
|
+
* add-ons, and Marionette cannot script privileged moz-extension pages — but
|
|
10
|
+
* the devtools server can install the exact .zip, report its manifest warnings
|
|
11
|
+
* and background status, and stream every error the add-on's documents raise.
|
|
12
|
+
*/
|
|
13
|
+
import { spawn } from 'node:child_process';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import net from 'node:net';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
export class RdpClient {
|
|
19
|
+
socket;
|
|
20
|
+
buffer = Buffer.alloc(0);
|
|
21
|
+
pending = [];
|
|
22
|
+
listeners = [];
|
|
23
|
+
constructor(socket) {
|
|
24
|
+
this.socket = socket;
|
|
25
|
+
socket.on('data', (chunk) => this.onData(chunk));
|
|
26
|
+
socket.on('close', () => {
|
|
27
|
+
for (const w of this.pending.splice(0))
|
|
28
|
+
w.reject(new Error('Firefox closed the debugging connection'));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** Connect, retrying while Firefox starts; resolves with the client and the server's hello packet. */
|
|
32
|
+
static async connect(port, timeoutMs) {
|
|
33
|
+
const deadline = Date.now() + timeoutMs;
|
|
34
|
+
for (;;) {
|
|
35
|
+
try {
|
|
36
|
+
const socket = await new Promise((resolve, reject) => {
|
|
37
|
+
const s = net.connect(port, '127.0.0.1', () => resolve(s));
|
|
38
|
+
s.once('error', reject);
|
|
39
|
+
});
|
|
40
|
+
const client = new RdpClient(socket);
|
|
41
|
+
const hello = await client.next((p) => p.from === 'root' && 'applicationType' in p, 5_000);
|
|
42
|
+
return { client, hello };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (Date.now() > deadline)
|
|
46
|
+
throw new Error(`Firefox did not open its debugging port within ${timeoutMs} ms (${error.message})`);
|
|
47
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
onData(chunk) {
|
|
52
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
53
|
+
for (;;) {
|
|
54
|
+
const colon = this.buffer.indexOf(0x3a);
|
|
55
|
+
if (colon < 0)
|
|
56
|
+
return;
|
|
57
|
+
const length = Number(this.buffer.subarray(0, colon).toString());
|
|
58
|
+
if (!Number.isFinite(length)) {
|
|
59
|
+
this.socket.destroy(new Error('malformed RDP packet'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.buffer.length < colon + 1 + length)
|
|
63
|
+
return;
|
|
64
|
+
const packet = JSON.parse(this.buffer.subarray(colon + 1, colon + 1 + length).toString('utf8'));
|
|
65
|
+
this.buffer = this.buffer.subarray(colon + 1 + length);
|
|
66
|
+
this.dispatch(packet);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
dispatch(packet) {
|
|
70
|
+
// Replies carry no `type` (or carry `error`); unsolicited events carry a type.
|
|
71
|
+
const isReply = packet.error !== undefined || packet.type === undefined;
|
|
72
|
+
const waiter = isReply ? this.pending.findIndex((w) => w.actor === packet.from) : -1;
|
|
73
|
+
if (waiter >= 0) {
|
|
74
|
+
this.pending.splice(waiter, 1)[0].resolve(packet);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const listener of this.listeners)
|
|
78
|
+
listener(packet);
|
|
79
|
+
}
|
|
80
|
+
on(listener) {
|
|
81
|
+
this.listeners.push(listener);
|
|
82
|
+
}
|
|
83
|
+
/** The next unsolicited packet matching `predicate`. */
|
|
84
|
+
next(predicate, timeoutMs) {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const timer = setTimeout(() => reject(new Error('timed out waiting for Firefox')), timeoutMs);
|
|
87
|
+
const listener = (p) => {
|
|
88
|
+
if (!predicate(p))
|
|
89
|
+
return;
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
this.listeners = this.listeners.filter((l) => l !== listener);
|
|
92
|
+
resolve(p);
|
|
93
|
+
};
|
|
94
|
+
this.listeners.push(listener);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
request(to, type, extra = {}, timeoutMs = 20_000) {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const timer = setTimeout(() => reject(new Error(`Firefox did not answer ${type}`)), timeoutMs);
|
|
100
|
+
this.pending.push({
|
|
101
|
+
actor: to,
|
|
102
|
+
resolve: (p) => {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
resolve(p);
|
|
105
|
+
},
|
|
106
|
+
reject: (e) => {
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
reject(e);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const body = Buffer.from(JSON.stringify({ to, type, ...extra }), 'utf8');
|
|
112
|
+
this.socket.write(`${body.length}:`);
|
|
113
|
+
this.socket.write(body);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
close() {
|
|
117
|
+
this.socket.destroy();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** A Firefox binary, or null. Order: explicit path, FIREFOX_BIN, the usual install locations, PATH. */
|
|
121
|
+
export function findFirefox(explicit, env = process.env) {
|
|
122
|
+
const candidates = [explicit, env.FIREFOX_BIN];
|
|
123
|
+
if (process.platform === 'darwin')
|
|
124
|
+
candidates.push('/Applications/Firefox.app/Contents/MacOS/firefox', '/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox', '/Applications/Firefox Nightly.app/Contents/MacOS/firefox');
|
|
125
|
+
else if (process.platform === 'win32')
|
|
126
|
+
for (const base of [env.ProgramFiles, env['ProgramFiles(x86)']])
|
|
127
|
+
if (base)
|
|
128
|
+
candidates.push(path.join(base, 'Mozilla Firefox', 'firefox.exe'));
|
|
129
|
+
else
|
|
130
|
+
candidates.push('/usr/bin/firefox', '/usr/lib/firefox/firefox', '/usr/local/bin/firefox');
|
|
131
|
+
for (const dir of (env.PATH ?? '').split(path.delimiter))
|
|
132
|
+
if (dir)
|
|
133
|
+
candidates.push(path.join(dir, process.platform === 'win32' ? 'firefox.exe' : 'firefox'));
|
|
134
|
+
for (const candidate of candidates)
|
|
135
|
+
if (candidate && fs.existsSync(candidate))
|
|
136
|
+
return candidate;
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
async function freePort() {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const server = net.createServer();
|
|
142
|
+
server.once('error', reject);
|
|
143
|
+
server.listen(0, '127.0.0.1', () => {
|
|
144
|
+
const address = server.address();
|
|
145
|
+
server.close(() => typeof address === 'object' && address ? resolve(address.port) : reject(new Error('no port')));
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Start a disposable headless Firefox with the devtools server on a free port.
|
|
151
|
+
* `uuids` pins the moz-extension:// host per add-on id, so extension pages have
|
|
152
|
+
* a known URL before the add-on is installed.
|
|
153
|
+
*/
|
|
154
|
+
export async function launchFirefox(options) {
|
|
155
|
+
const profile = fs.mkdtempSync(path.join(os.tmpdir(), 'extenshi-smoke-firefox-'));
|
|
156
|
+
const prefs = {
|
|
157
|
+
'devtools.debugger.remote-enabled': true,
|
|
158
|
+
'devtools.debugger.prompt-connection': false,
|
|
159
|
+
'devtools.chrome.enabled': true,
|
|
160
|
+
'browser.shell.checkDefaultBrowser': false,
|
|
161
|
+
'browser.startup.homepage_override.mstone': 'ignore',
|
|
162
|
+
'browser.aboutwelcome.enabled': false,
|
|
163
|
+
'datareporting.policy.dataSubmissionEnabled': false,
|
|
164
|
+
'toolkit.telemetry.reportingpolicy.firstRun': false,
|
|
165
|
+
'app.update.enabled': false,
|
|
166
|
+
'extensions.webextensions.uuids': JSON.stringify(options.uuids),
|
|
167
|
+
};
|
|
168
|
+
fs.writeFileSync(path.join(profile, 'user.js'), Object.entries(prefs)
|
|
169
|
+
.map(([key, value]) => `user_pref(${JSON.stringify(key)}, ${JSON.stringify(value)});`)
|
|
170
|
+
.join('\n'));
|
|
171
|
+
const port = await freePort();
|
|
172
|
+
const args = ['-no-remote', '-profile', profile, '-start-debugger-server', String(port)];
|
|
173
|
+
if (options.headless)
|
|
174
|
+
args.unshift('-headless');
|
|
175
|
+
const child = spawn(options.binary, args, {
|
|
176
|
+
stdio: 'ignore',
|
|
177
|
+
env: { ...process.env, ...(options.headless ? { MOZ_HEADLESS: '1' } : {}) },
|
|
178
|
+
});
|
|
179
|
+
const exited = new Promise((resolve) => child.once('exit', () => resolve()));
|
|
180
|
+
const close = async () => {
|
|
181
|
+
child.kill();
|
|
182
|
+
await Promise.race([exited, new Promise((r) => setTimeout(r, 5_000))]);
|
|
183
|
+
fs.rmSync(profile, { recursive: true, force: true });
|
|
184
|
+
};
|
|
185
|
+
try {
|
|
186
|
+
const { client, hello } = await RdpClient.connect(port, options.timeoutMs);
|
|
187
|
+
return {
|
|
188
|
+
client,
|
|
189
|
+
hello,
|
|
190
|
+
process: child,
|
|
191
|
+
profile,
|
|
192
|
+
close: async () => {
|
|
193
|
+
client.close();
|
|
194
|
+
await close();
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
await close();
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=firefox-rdp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firefox-rdp.js","sourceRoot":"","sources":["../src/firefox-rdp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firefox add-on ID (`browser_specific_settings.gecko.id`) rules, shared by the
|
|
3
|
+
* manifest builder, the Dojo validator, the standalone CLI packager and the
|
|
4
|
+
* owner-decisions registry (the suggested `amo.addonId` IS `projectGeckoId`).
|
|
5
|
+
*
|
|
6
|
+
* SINGLE SOURCE, THREE COPIES: this file exists byte-identical at
|
|
7
|
+
* shared-types/gecko-id.ts (canonical — edit here)
|
|
8
|
+
* tools/extenshi-cli/src/gecko-id.ts (synced copy for the published CLI)
|
|
9
|
+
* tools/extenshi-contracts/src/gecko-id.ts (synced copy for @extenshi/contracts)
|
|
10
|
+
* because `@extenshi/cli` and `@extenshi/contracts` ship to npm on their own and
|
|
11
|
+
* cannot import workspace shared-types at runtime. `tools/extenshi-cli/src/
|
|
12
|
+
* package-sync.test.ts` and `tools/extenshi-contracts/test/sync.test.ts` fail CI
|
|
13
|
+
* when the copies drift; after editing, run:
|
|
14
|
+
* cp shared-types/gecko-id.ts tools/extenshi-cli/src/gecko-id.ts
|
|
15
|
+
* yarn workspace @extenshi/contracts sync
|
|
16
|
+
* (landings vendors it too: `node landings/scripts/sync-vendor.mjs --write`.)
|
|
17
|
+
*
|
|
18
|
+
* Deliberately dependency-free and synchronous: the manifest builder runs in the
|
|
19
|
+
* browser (Dojo), in catalog-bff and in the CLI, and one of those has no
|
|
20
|
+
* node:crypto while another has no synchronous WebCrypto.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* What the manifest builder writes when it knows nothing better. AMO accepts it
|
|
24
|
+
* syntactically, which is exactly the problem: an add-on uploaded under it owns
|
|
25
|
+
* that ID forever, so it must never reach a store package.
|
|
26
|
+
*/
|
|
27
|
+
export declare const PLACEHOLDER_GECKO_ID = "extension@example.com";
|
|
28
|
+
/** An ID AMO would accept at all (shape only — says nothing about ownership). */
|
|
29
|
+
export declare function isValidGeckoId(id: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* An ID that is syntactically fine but obviously nobody's: the builder's own
|
|
32
|
+
* placeholder, anything on the reserved example domains (docs and blog posts
|
|
33
|
+
* use `my-extension@example.com`), and the all-zero GUID.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isPlaceholderGeckoId(id: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The default Firefox add-on ID for a Dojo project: `{<uuid>}` derived from the
|
|
38
|
+
* project id, so every build of the project agrees on it without anyone storing
|
|
39
|
+
* it, and the value reveals neither the project id nor extenshi.io.
|
|
40
|
+
*
|
|
41
|
+
* Derivation (reproducible with any SHA-256 tool): take the first 16 bytes of
|
|
42
|
+
* `sha256("extenshi-gecko-id:v1:" + projectId.toLowerCase())`, set the UUID
|
|
43
|
+
* version nibble to 8 (RFC 9562 "custom") and the variant bits to 10, and format
|
|
44
|
+
* as a braced GUID.
|
|
45
|
+
*
|
|
46
|
+
* NEVER change this function's output. AMO makes an add-on ID immutable after the
|
|
47
|
+
* first upload, so a project that shipped with the derived default is bound to
|
|
48
|
+
* exactly this value. A developer who wants another ID sets it explicitly (the
|
|
49
|
+
* "Firefox add-on ID" field / `--gecko-id`) BEFORE the first AMO upload; the
|
|
50
|
+
* pinned test in gecko-id.test.ts guards the derivation.
|
|
51
|
+
*/
|
|
52
|
+
export declare function projectGeckoId(projectId: string): string;
|
|
53
|
+
/** Exported for the test that checks it against node:crypto; not a general-purpose API. */
|
|
54
|
+
export declare function sha256(text: string): Uint8Array;
|
|
55
|
+
//# sourceMappingURL=gecko-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gecko-id.d.ts","sourceRoot":"","sources":["../src/gecko-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,0BAA0B,CAAA;AAM3D,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMxD;AAeD,2FAA2F;AAC3F,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAgD/C"}
|
package/dist/gecko-id.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firefox add-on ID (`browser_specific_settings.gecko.id`) rules, shared by the
|
|
3
|
+
* manifest builder, the Dojo validator, the standalone CLI packager and the
|
|
4
|
+
* owner-decisions registry (the suggested `amo.addonId` IS `projectGeckoId`).
|
|
5
|
+
*
|
|
6
|
+
* SINGLE SOURCE, THREE COPIES: this file exists byte-identical at
|
|
7
|
+
* shared-types/gecko-id.ts (canonical — edit here)
|
|
8
|
+
* tools/extenshi-cli/src/gecko-id.ts (synced copy for the published CLI)
|
|
9
|
+
* tools/extenshi-contracts/src/gecko-id.ts (synced copy for @extenshi/contracts)
|
|
10
|
+
* because `@extenshi/cli` and `@extenshi/contracts` ship to npm on their own and
|
|
11
|
+
* cannot import workspace shared-types at runtime. `tools/extenshi-cli/src/
|
|
12
|
+
* package-sync.test.ts` and `tools/extenshi-contracts/test/sync.test.ts` fail CI
|
|
13
|
+
* when the copies drift; after editing, run:
|
|
14
|
+
* cp shared-types/gecko-id.ts tools/extenshi-cli/src/gecko-id.ts
|
|
15
|
+
* yarn workspace @extenshi/contracts sync
|
|
16
|
+
* (landings vendors it too: `node landings/scripts/sync-vendor.mjs --write`.)
|
|
17
|
+
*
|
|
18
|
+
* Deliberately dependency-free and synchronous: the manifest builder runs in the
|
|
19
|
+
* browser (Dojo), in catalog-bff and in the CLI, and one of those has no
|
|
20
|
+
* node:crypto while another has no synchronous WebCrypto.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* What the manifest builder writes when it knows nothing better. AMO accepts it
|
|
24
|
+
* syntactically, which is exactly the problem: an add-on uploaded under it owns
|
|
25
|
+
* that ID forever, so it must never reach a store package.
|
|
26
|
+
*/
|
|
27
|
+
export const PLACEHOLDER_GECKO_ID = 'extension@example.com';
|
|
28
|
+
const GUID_RE = /^\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}$/;
|
|
29
|
+
// AMO's own two accepted shapes: a GUID in braces, or an email-like string.
|
|
30
|
+
const EMAIL_LIKE_RE = /^[a-zA-Z0-9-._]*@[a-zA-Z0-9-._]+$/;
|
|
31
|
+
/** An ID AMO would accept at all (shape only — says nothing about ownership). */
|
|
32
|
+
export function isValidGeckoId(id) {
|
|
33
|
+
const value = id.trim();
|
|
34
|
+
return value.length > 0 && value.length <= 255 && (GUID_RE.test(value) || EMAIL_LIKE_RE.test(value));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* An ID that is syntactically fine but obviously nobody's: the builder's own
|
|
38
|
+
* placeholder, anything on the reserved example domains (docs and blog posts
|
|
39
|
+
* use `my-extension@example.com`), and the all-zero GUID.
|
|
40
|
+
*/
|
|
41
|
+
export function isPlaceholderGeckoId(id) {
|
|
42
|
+
const value = id.trim().toLowerCase();
|
|
43
|
+
return (value === PLACEHOLDER_GECKO_ID ||
|
|
44
|
+
/@example\.(?:com|org|net)$/.test(value) ||
|
|
45
|
+
value === '{00000000-0000-0000-0000-000000000000}');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The default Firefox add-on ID for a Dojo project: `{<uuid>}` derived from the
|
|
49
|
+
* project id, so every build of the project agrees on it without anyone storing
|
|
50
|
+
* it, and the value reveals neither the project id nor extenshi.io.
|
|
51
|
+
*
|
|
52
|
+
* Derivation (reproducible with any SHA-256 tool): take the first 16 bytes of
|
|
53
|
+
* `sha256("extenshi-gecko-id:v1:" + projectId.toLowerCase())`, set the UUID
|
|
54
|
+
* version nibble to 8 (RFC 9562 "custom") and the variant bits to 10, and format
|
|
55
|
+
* as a braced GUID.
|
|
56
|
+
*
|
|
57
|
+
* NEVER change this function's output. AMO makes an add-on ID immutable after the
|
|
58
|
+
* first upload, so a project that shipped with the derived default is bound to
|
|
59
|
+
* exactly this value. A developer who wants another ID sets it explicitly (the
|
|
60
|
+
* "Firefox add-on ID" field / `--gecko-id`) BEFORE the first AMO upload; the
|
|
61
|
+
* pinned test in gecko-id.test.ts guards the derivation.
|
|
62
|
+
*/
|
|
63
|
+
export function projectGeckoId(projectId) {
|
|
64
|
+
const bytes = sha256(`extenshi-gecko-id:v1:${projectId.trim().toLowerCase()}`).slice(0, 16);
|
|
65
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x80;
|
|
66
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
67
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
68
|
+
return `{${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}}`;
|
|
69
|
+
}
|
|
70
|
+
// ── SHA-256 (FIPS 180-4), synchronous, over the UTF-8 bytes of a string ─────
|
|
71
|
+
const K = new Uint32Array([
|
|
72
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
|
|
73
|
+
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
74
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
|
|
75
|
+
0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
76
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
|
77
|
+
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
78
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
|
79
|
+
0xc67178f2,
|
|
80
|
+
]);
|
|
81
|
+
/** Exported for the test that checks it against node:crypto; not a general-purpose API. */
|
|
82
|
+
export function sha256(text) {
|
|
83
|
+
const input = new TextEncoder().encode(text);
|
|
84
|
+
const bitLength = input.length * 8;
|
|
85
|
+
const padded = new Uint8Array(Math.ceil((input.length + 9) / 64) * 64);
|
|
86
|
+
padded.set(input);
|
|
87
|
+
padded[input.length] = 0x80;
|
|
88
|
+
const view = new DataView(padded.buffer);
|
|
89
|
+
view.setUint32(padded.length - 8, Math.floor(bitLength / 0x100000000), false);
|
|
90
|
+
view.setUint32(padded.length - 4, bitLength >>> 0, false);
|
|
91
|
+
const h = new Uint32Array([
|
|
92
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
93
|
+
]);
|
|
94
|
+
const w = new Uint32Array(64);
|
|
95
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
96
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
97
|
+
for (let i = 0; i < 16; i++)
|
|
98
|
+
w[i] = view.getUint32(offset + i * 4, false);
|
|
99
|
+
for (let i = 16; i < 64; i++) {
|
|
100
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
101
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
102
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
103
|
+
}
|
|
104
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
105
|
+
for (let i = 0; i < 64; i++) {
|
|
106
|
+
const t1 = (hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + K[i] + w[i]) >>> 0;
|
|
107
|
+
const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
|
|
108
|
+
hh = g;
|
|
109
|
+
g = f;
|
|
110
|
+
f = e;
|
|
111
|
+
e = (d + t1) >>> 0;
|
|
112
|
+
d = c;
|
|
113
|
+
c = b;
|
|
114
|
+
b = a;
|
|
115
|
+
a = (t1 + t2) >>> 0;
|
|
116
|
+
}
|
|
117
|
+
h[0] = (h[0] + a) >>> 0;
|
|
118
|
+
h[1] = (h[1] + b) >>> 0;
|
|
119
|
+
h[2] = (h[2] + c) >>> 0;
|
|
120
|
+
h[3] = (h[3] + d) >>> 0;
|
|
121
|
+
h[4] = (h[4] + e) >>> 0;
|
|
122
|
+
h[5] = (h[5] + f) >>> 0;
|
|
123
|
+
h[6] = (h[6] + g) >>> 0;
|
|
124
|
+
h[7] = (h[7] + hh) >>> 0;
|
|
125
|
+
}
|
|
126
|
+
const out = new Uint8Array(32);
|
|
127
|
+
const outView = new DataView(out.buffer);
|
|
128
|
+
for (let i = 0; i < 8; i++)
|
|
129
|
+
outView.setUint32(i * 4, h[i], false);
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=gecko-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gecko-id.js","sourceRoot":"","sources":["../src/gecko-id.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `extenshi generate-listing <artifact
|
|
3
|
-
* package (ROADMAP it.2 T11
|
|
2
|
+
* `extenshi generate-listing <artifact> [--store chrome|edge|firefox]` — write
|
|
3
|
+
* a per-store listing draft from a live package (ROADMAP it.2 T11; Edge/AMO
|
|
4
|
+
* added as part of the "Edge and Firefox are first-class" gap-analysis item).
|
|
4
5
|
*
|
|
5
6
|
* Pure transform: listing text (manifest + optional `--listing`) + the
|
|
6
7
|
* justification checklist (it.1 T6) + the privacy-disclosure checklist (it.2 T5)
|
|
7
|
-
* → markdown. The CLI only
|
|
8
|
-
*
|
|
8
|
+
* + (edge/firefox) store-specific manifest facts → markdown. The CLI only
|
|
9
|
+
* loads the artifact and writes the file. It does NOT write listing / Privacy
|
|
10
|
+
* / visibility into any store dashboard.
|
|
9
11
|
*
|
|
10
|
-
* `review-risk --listing
|
|
11
|
-
*
|
|
12
|
+
* `review-risk --listing <file>` is the consumer for all three outputs — they
|
|
13
|
+
* share the Name / Short description / Description / Single purpose headings
|
|
14
|
+
* with CHROMEWEBSTORE.md, so `listingDraftFromChromeWebStoreMd` (keyed on
|
|
15
|
+
* headings, not filename) parses EDGE.md/AMO.md exactly the same way.
|
|
12
16
|
*/
|
|
13
17
|
import { type FileMap, type Manifest } from './review-checks.js';
|
|
18
|
+
export type ListingStore = 'chrome' | 'edge' | 'firefox';
|
|
14
19
|
export interface GenerateListingInput {
|
|
15
20
|
manifest: Manifest;
|
|
16
21
|
files: FileMap;
|
|
17
22
|
listingPath?: string;
|
|
23
|
+
/** Which store's draft to render. Defaults to `'chrome'` for backward compatibility. */
|
|
24
|
+
store?: ListingStore;
|
|
18
25
|
}
|
|
19
26
|
/**
|
|
20
|
-
* Assemble
|
|
27
|
+
* Assemble a listing draft from an already-loaded package. No I/O except
|
|
21
28
|
* reading `--listing` through `assembleListing` when a path is passed.
|
|
22
29
|
*/
|
|
30
|
+
export declare function generateListingMdFromPackage(input: GenerateListingInput): string;
|
|
31
|
+
/** @deprecated kept for existing callers/tests — same as `generateListingMdFromPackage` with `store: 'chrome'`. */
|
|
23
32
|
export declare function generateChromeWebStoreMdFromPackage(input: GenerateListingInput): string;
|
|
24
33
|
export interface GenerateListingOptions {
|
|
25
34
|
artifactPath: string;
|
|
26
|
-
/** Where to write the markdown. Default:
|
|
35
|
+
/** Where to write the markdown. Default: the per-store filename in cwd. */
|
|
27
36
|
outputPath?: string;
|
|
28
37
|
listingPath?: string;
|
|
38
|
+
/** Which store's draft to render. Defaults to `'chrome'` for backward compatibility. */
|
|
39
|
+
store?: ListingStore;
|
|
29
40
|
}
|
|
30
41
|
export declare function runGenerateListing(opts: GenerateListingOptions): Promise<string>;
|
|
31
42
|
//# sourceMappingURL=generate-listing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-listing.d.ts","sourceRoot":"","sources":["../src/generate-listing.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"generate-listing.d.ts","sourceRoot":"","sources":["../src/generate-listing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAA+B,MAAM,oBAAoB,CAAA;AAQ7F,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;AAMxD,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,QAAQ,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,KAAK,CAAC,EAAE,YAAY,CAAA;CACpB;AAQD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAyChF;AAED,mHAAmH;AACnH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAEvF;AAED,MAAM,WAAW,sBAAsB;IACtC,YAAY,EAAE,MAAM,CAAA;IACpB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,KAAK,CAAC,EAAE,YAAY,CAAA;CACpB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBtF"}
|
package/dist/generate-listing.js
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `extenshi generate-listing <artifact
|
|
3
|
-
* package (ROADMAP it.2 T11
|
|
2
|
+
* `extenshi generate-listing <artifact> [--store chrome|edge|firefox]` — write
|
|
3
|
+
* a per-store listing draft from a live package (ROADMAP it.2 T11; Edge/AMO
|
|
4
|
+
* added as part of the "Edge and Firefox are first-class" gap-analysis item).
|
|
4
5
|
*
|
|
5
6
|
* Pure transform: listing text (manifest + optional `--listing`) + the
|
|
6
7
|
* justification checklist (it.1 T6) + the privacy-disclosure checklist (it.2 T5)
|
|
7
|
-
* → markdown. The CLI only
|
|
8
|
-
*
|
|
8
|
+
* + (edge/firefox) store-specific manifest facts → markdown. The CLI only
|
|
9
|
+
* loads the artifact and writes the file. It does NOT write listing / Privacy
|
|
10
|
+
* / visibility into any store dashboard.
|
|
9
11
|
*
|
|
10
|
-
* `review-risk --listing
|
|
11
|
-
*
|
|
12
|
+
* `review-risk --listing <file>` is the consumer for all three outputs — they
|
|
13
|
+
* share the Name / Short description / Description / Single purpose headings
|
|
14
|
+
* with CHROMEWEBSTORE.md, so `listingDraftFromChromeWebStoreMd` (keyed on
|
|
15
|
+
* headings, not filename) parses EDGE.md/AMO.md exactly the same way.
|
|
12
16
|
*/
|
|
13
17
|
import fs from 'node:fs';
|
|
14
18
|
import path from 'node:path';
|
|
19
|
+
import { detectMinifiedFiles } from './amo-source-detect.js';
|
|
20
|
+
import { AMO_FILENAME, renderAmoMd } from './amowebstore-md.js';
|
|
15
21
|
import { CHROMEWEBSTORE_FILENAME, renderChromeWebStoreMd } from './chromewebstore-md.js';
|
|
22
|
+
import { EDGE_FILENAME, renderEdgeMd } from './edgewebstore-md.js';
|
|
16
23
|
import { assembleListing } from './listing.js';
|
|
17
24
|
import { buildJustificationChecklist } from './permission-justifications.js';
|
|
18
25
|
import { loadArtifact } from './review-archive.js';
|
|
@@ -22,41 +29,82 @@ const MAX_ENTRY_BYTES = 4 * 1024 * 1024;
|
|
|
22
29
|
const MAX_TOTAL_BYTES = 40 * 1024 * 1024;
|
|
23
30
|
const TEXT_ENTRY_RE = /\.(?:m?js|cjs|html?|json)$/i;
|
|
24
31
|
const SKIP_DIRS = new Set(['node_modules', '.git', '.yarn']);
|
|
32
|
+
// Placeholder gecko ids a scaffold/template might ship — same list
|
|
33
|
+
// store_compliance/firefox/src/checks/manifest-hygiene.ts treats as "not really set".
|
|
34
|
+
const PLACEHOLDER_GECKO_IDS = new Set(['extension@example.com', '@example', 'my-addon-id@example.org']);
|
|
35
|
+
function filenameForStore(store) {
|
|
36
|
+
if (store === 'edge')
|
|
37
|
+
return EDGE_FILENAME;
|
|
38
|
+
if (store === 'firefox')
|
|
39
|
+
return AMO_FILENAME;
|
|
40
|
+
return CHROMEWEBSTORE_FILENAME;
|
|
41
|
+
}
|
|
25
42
|
/**
|
|
26
|
-
* Assemble
|
|
43
|
+
* Assemble a listing draft from an already-loaded package. No I/O except
|
|
27
44
|
* reading `--listing` through `assembleListing` when a path is passed.
|
|
28
45
|
*/
|
|
29
|
-
export function
|
|
46
|
+
export function generateListingMdFromPackage(input) {
|
|
47
|
+
const store = input.store ?? 'chrome';
|
|
30
48
|
const listing = assembleListing(input.manifest, input.files, input.listingPath);
|
|
31
49
|
const justifications = buildJustificationChecklist(input.manifest).map((row) => ({
|
|
32
50
|
permission: row.permission,
|
|
33
51
|
prompt: `${row.question}\n\nExample: ${row.example}`,
|
|
34
52
|
}));
|
|
35
|
-
const privacy = privacyPracticesForManifest(input.manifest);
|
|
36
53
|
const loc = listing?.locales.find((l) => l.locale === listing.defaultLocale) ?? listing?.locales[0];
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
const singlePurpose = loc?.shortDescription ?? loc?.name ?? '';
|
|
55
|
+
if (store === 'edge') {
|
|
56
|
+
const privacy = privacyPracticesForManifest(input.manifest);
|
|
57
|
+
return renderEdgeMd({
|
|
58
|
+
listing,
|
|
59
|
+
justifications,
|
|
60
|
+
needsPrivacyPolicy: privacy.length > 0,
|
|
61
|
+
singlePurpose,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (store === 'firefox') {
|
|
65
|
+
const gecko = input.manifest.browser_specific_settings?.gecko;
|
|
66
|
+
const required = gecko?.data_collection_permissions?.required;
|
|
67
|
+
return renderAmoMd({
|
|
68
|
+
listing,
|
|
69
|
+
justifications,
|
|
70
|
+
singlePurpose,
|
|
71
|
+
gecko: {
|
|
72
|
+
id: gecko?.id,
|
|
73
|
+
isPlaceholder: gecko?.id ? PLACEHOLDER_GECKO_IDS.has(gecko.id.toLowerCase()) : false,
|
|
74
|
+
strictMinVersion: gecko?.strict_min_version,
|
|
75
|
+
dataCollectionRequired: Array.isArray(required)
|
|
76
|
+
? required.filter((v) => typeof v === 'string')
|
|
77
|
+
: undefined,
|
|
78
|
+
},
|
|
79
|
+
minifiedFiles: detectMinifiedFiles(input.files),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const privacy = privacyPracticesForManifest(input.manifest);
|
|
83
|
+
return renderChromeWebStoreMd({ listing, justifications, privacy, singlePurpose });
|
|
84
|
+
}
|
|
85
|
+
/** @deprecated kept for existing callers/tests — same as `generateListingMdFromPackage` with `store: 'chrome'`. */
|
|
86
|
+
export function generateChromeWebStoreMdFromPackage(input) {
|
|
87
|
+
return generateListingMdFromPackage({ ...input, store: 'chrome' });
|
|
43
88
|
}
|
|
44
89
|
export async function runGenerateListing(opts) {
|
|
45
90
|
if (!fs.existsSync(opts.artifactPath)) {
|
|
46
91
|
throw new Error(`Artifact file not found: ${opts.artifactPath}`);
|
|
47
92
|
}
|
|
93
|
+
const store = opts.store ?? 'chrome';
|
|
48
94
|
const { manifest, files } = await loadPackage(opts.artifactPath);
|
|
49
|
-
const markdown =
|
|
95
|
+
const markdown = generateListingMdFromPackage({
|
|
50
96
|
manifest,
|
|
51
97
|
files,
|
|
52
98
|
listingPath: opts.listingPath,
|
|
99
|
+
store,
|
|
53
100
|
});
|
|
54
|
-
const outputPath = path.resolve(opts.outputPath ??
|
|
101
|
+
const outputPath = path.resolve(opts.outputPath ?? filenameForStore(store));
|
|
55
102
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
56
103
|
fs.writeFileSync(outputPath, markdown, 'utf8');
|
|
104
|
+
const storeName = store === 'edge' ? 'Microsoft Edge Add-ons' : store === 'firefox' ? 'AMO' : 'Chrome Web Store';
|
|
57
105
|
process.stdout.write(`Wrote ${outputPath}\n` +
|
|
58
106
|
'This is the same listing draft `review-risk --listing` accepts. ' +
|
|
59
|
-
|
|
107
|
+
`Fill the ${storeName} dashboard by hand — the CLI does not write to the store.\n`);
|
|
60
108
|
return outputPath;
|
|
61
109
|
}
|
|
62
110
|
async function loadPackage(artifactPath) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-listing.js","sourceRoot":"","sources":["../src/generate-listing.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"generate-listing.js","sourceRoot":"","sources":["../src/generate-listing.ts"],"names":[],"mappings":"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"}
|