@extension.dev/deploy 0.1.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +237 -0
  3. package/bin/extension-deploy.cjs +3 -0
  4. package/dist/__tests__/cli.test.d.ts +2 -0
  5. package/dist/__tests__/cli.test.d.ts.map +1 -0
  6. package/dist/__tests__/config.test.d.ts +2 -0
  7. package/dist/__tests__/config.test.d.ts.map +1 -0
  8. package/dist/__tests__/deploy.test.d.ts +2 -0
  9. package/dist/__tests__/deploy.test.d.ts.map +1 -0
  10. package/dist/__tests__/dry-run.test.d.ts +2 -0
  11. package/dist/__tests__/dry-run.test.d.ts.map +1 -0
  12. package/dist/__tests__/types.test.d.ts +2 -0
  13. package/dist/__tests__/types.test.d.ts.map +1 -0
  14. package/dist/__tests__/utils.test.d.ts +2 -0
  15. package/dist/__tests__/utils.test.d.ts.map +1 -0
  16. package/dist/__tests__/verify.test.d.ts +2 -0
  17. package/dist/__tests__/verify.test.d.ts.map +1 -0
  18. package/dist/__tests__/watch.test.d.ts +2 -0
  19. package/dist/__tests__/watch.test.d.ts.map +1 -0
  20. package/dist/module.d.ts +2 -0
  21. package/dist/module.d.ts.map +1 -0
  22. package/dist/module.js +976 -0
  23. package/dist/module.mjs +886 -0
  24. package/dist/src/chrome.d.ts +42 -0
  25. package/dist/src/chrome.d.ts.map +1 -0
  26. package/dist/src/cli.d.ts +4 -0
  27. package/dist/src/cli.d.ts.map +1 -0
  28. package/dist/src/config.d.ts +68 -0
  29. package/dist/src/config.d.ts.map +1 -0
  30. package/dist/src/deploy.d.ts +3 -0
  31. package/dist/src/deploy.d.ts.map +1 -0
  32. package/dist/src/edge.d.ts +39 -0
  33. package/dist/src/edge.d.ts.map +1 -0
  34. package/dist/src/firefox.d.ts +56 -0
  35. package/dist/src/firefox.d.ts.map +1 -0
  36. package/dist/src/index.d.ts +14 -0
  37. package/dist/src/index.d.ts.map +1 -0
  38. package/dist/src/types.d.ts +242 -0
  39. package/dist/src/types.d.ts.map +1 -0
  40. package/dist/src/utils/async.d.ts +2 -0
  41. package/dist/src/utils/async.d.ts.map +1 -0
  42. package/dist/src/utils/fetch.d.ts +3 -0
  43. package/dist/src/utils/fetch.d.ts.map +1 -0
  44. package/dist/src/utils/fs.d.ts +4 -0
  45. package/dist/src/utils/fs.d.ts.map +1 -0
  46. package/dist/src/utils/log.d.ts +6 -0
  47. package/dist/src/utils/log.d.ts.map +1 -0
  48. package/dist/src/watch.d.ts +41 -0
  49. package/dist/src/watch.d.ts.map +1 -0
  50. package/package.json +78 -0
package/dist/module.js ADDED
@@ -0,0 +1,976 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
12
+ (()=>{
13
+ __webpack_require__.d = (exports1, definition)=>{
14
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
15
+ enumerable: true,
16
+ get: definition[key]
17
+ });
18
+ };
19
+ })();
20
+ (()=>{
21
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
22
+ })();
23
+ (()=>{
24
+ __webpack_require__.r = (exports1)=>{
25
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
26
+ value: 'Module'
27
+ });
28
+ Object.defineProperty(exports1, '__esModule', {
29
+ value: true
30
+ });
31
+ };
32
+ })();
33
+ var __webpack_exports__ = {};
34
+ __webpack_require__.r(__webpack_exports__);
35
+ __webpack_require__.d(__webpack_exports__, {
36
+ getEdgeSubmissionEvent: ()=>getEdgeSubmissionEvent,
37
+ resolveConfig: ()=>resolveConfig,
38
+ chromeOptionsSchema: ()=>chromeOptionsSchema,
39
+ getFirefoxSubmissionEvent: ()=>getFirefoxSubmissionEvent,
40
+ edgeOptionsSchema: ()=>edgeOptionsSchema,
41
+ deployConfigSchema: ()=>deployConfigSchema,
42
+ getChromeSubmissionEvent: ()=>getChromeSubmissionEvent,
43
+ watchFirefoxSubmission: ()=>watchFirefoxSubmission,
44
+ watchEdgeSubmission: ()=>watchEdgeSubmission,
45
+ firefoxOptionsSchema: ()=>firefoxOptionsSchema,
46
+ validateConfig: ()=>validateConfig,
47
+ deploy: ()=>deploy,
48
+ verifyFirefoxCredentials: ()=>verifyFirefoxCredentials,
49
+ verifyEdgeCredentials: ()=>verifyEdgeCredentials,
50
+ verifyChromeCredentials: ()=>verifyChromeCredentials,
51
+ watchChromeSubmission: ()=>watchChromeSubmission
52
+ });
53
+ const external_zod_namespaceObject = require("zod");
54
+ const chromeOptionsSchema = external_zod_namespaceObject.z.object({
55
+ zip: external_zod_namespaceObject.z.string().min(1),
56
+ extensionId: external_zod_namespaceObject.z.string().min(1).trim(),
57
+ clientId: external_zod_namespaceObject.z.string().min(1).trim(),
58
+ clientSecret: external_zod_namespaceObject.z.string().min(1).trim(),
59
+ refreshToken: external_zod_namespaceObject.z.string().min(1).trim(),
60
+ publishTarget: external_zod_namespaceObject.z["enum"]([
61
+ "default",
62
+ "trustedTesters"
63
+ ]).default("default"),
64
+ deployPercentage: external_zod_namespaceObject.z.number().int().min(1).max(100).optional(),
65
+ reviewExemption: external_zod_namespaceObject.z.boolean().default(false),
66
+ skipSubmitReview: external_zod_namespaceObject.z.boolean().default(false)
67
+ });
68
+ const firefoxOptionsSchema = external_zod_namespaceObject.z.object({
69
+ zip: external_zod_namespaceObject.z.string().min(1),
70
+ sourcesZip: external_zod_namespaceObject.z.string().min(1).optional(),
71
+ extensionId: external_zod_namespaceObject.z.string().min(1).trim(),
72
+ jwtIssuer: external_zod_namespaceObject.z.string().min(1).trim(),
73
+ jwtSecret: external_zod_namespaceObject.z.string().min(1).trim(),
74
+ channel: external_zod_namespaceObject.z["enum"]([
75
+ "listed",
76
+ "unlisted"
77
+ ]).default("listed")
78
+ });
79
+ const edgeOptionsSchema = external_zod_namespaceObject.z.object({
80
+ zip: external_zod_namespaceObject.z.string().min(1),
81
+ productId: external_zod_namespaceObject.z.string().min(1).trim(),
82
+ clientId: external_zod_namespaceObject.z.string().min(1).trim(),
83
+ apiKey: external_zod_namespaceObject.z.string().min(1).trim(),
84
+ skipSubmitReview: external_zod_namespaceObject.z.boolean().default(false)
85
+ });
86
+ const deployConfigSchema = external_zod_namespaceObject.z.object({
87
+ dryRun: external_zod_namespaceObject.z.boolean().default(false),
88
+ chrome: chromeOptionsSchema.optional(),
89
+ firefox: firefoxOptionsSchema.optional(),
90
+ edge: edgeOptionsSchema.optional()
91
+ });
92
+ function resolveConfig(flags) {
93
+ const dryRun = flags.dryRun ?? envBool("DRY_RUN") ?? false;
94
+ const chromeZip = flags.chromeZip ?? envStr("CHROME_ZIP");
95
+ const firefoxZip = flags.firefoxZip ?? envStr("FIREFOX_ZIP");
96
+ const edgeZip = flags.edgeZip ?? envStr("EDGE_ZIP");
97
+ return {
98
+ dryRun,
99
+ chrome: null == chromeZip ? void 0 : {
100
+ zip: chromeZip,
101
+ extensionId: flags.chromeExtensionId ?? envStr("CHROME_EXTENSION_ID") ?? "",
102
+ clientId: flags.chromeClientId ?? envStr("CHROME_CLIENT_ID") ?? "",
103
+ clientSecret: flags.chromeClientSecret ?? envStr("CHROME_CLIENT_SECRET") ?? "",
104
+ refreshToken: flags.chromeRefreshToken ?? envStr("CHROME_REFRESH_TOKEN") ?? "",
105
+ publishTarget: flags.chromePublishTarget ?? envStr("CHROME_PUBLISH_TARGET"),
106
+ deployPercentage: flags.chromeDeployPercentage ?? envInt("CHROME_DEPLOY_PERCENTAGE"),
107
+ reviewExemption: flags.chromeReviewExemption ?? envBool("CHROME_REVIEW_EXEMPTION"),
108
+ skipSubmitReview: flags.chromeSkipSubmitReview ?? envBool("CHROME_SKIP_SUBMIT_REVIEW")
109
+ },
110
+ firefox: null == firefoxZip ? void 0 : {
111
+ zip: firefoxZip,
112
+ sourcesZip: flags.firefoxSourcesZip ?? envStr("FIREFOX_SOURCES_ZIP"),
113
+ extensionId: flags.firefoxExtensionId ?? envStr("FIREFOX_EXTENSION_ID") ?? "",
114
+ jwtIssuer: flags.firefoxJwtIssuer ?? envStr("FIREFOX_JWT_ISSUER") ?? "",
115
+ jwtSecret: flags.firefoxJwtSecret ?? envStr("FIREFOX_JWT_SECRET") ?? "",
116
+ channel: flags.firefoxChannel ?? envStr("FIREFOX_CHANNEL")
117
+ },
118
+ edge: null == edgeZip ? void 0 : {
119
+ zip: edgeZip,
120
+ productId: flags.edgeProductId ?? envStr("EDGE_PRODUCT_ID") ?? "",
121
+ clientId: flags.edgeClientId ?? envStr("EDGE_CLIENT_ID") ?? "",
122
+ apiKey: flags.edgeApiKey ?? envStr("EDGE_API_KEY") ?? "",
123
+ skipSubmitReview: flags.edgeSkipSubmitReview ?? envBool("EDGE_SKIP_SUBMIT_REVIEW")
124
+ }
125
+ };
126
+ }
127
+ function pathToEnvName(segments) {
128
+ return segments.map((s)=>String(s).replace(/[A-Z]/g, (ch)=>`_${ch}`).toUpperCase()).join("_");
129
+ }
130
+ const SETUP_HINTS = {
131
+ CHROME_EXTENSION_ID: "Find this in the Chrome Web Store Developer Dashboard URL for your extension.",
132
+ CHROME_CLIENT_ID: "Create OAuth 2.0 credentials at https://console.cloud.google.com/apis/credentials",
133
+ CHROME_CLIENT_SECRET: "Generated alongside the Client ID in the Google Cloud Console.",
134
+ CHROME_REFRESH_TOKEN: "Obtain by completing the OAuth consent flow. See the Chrome Web Store API docs.",
135
+ CHROME_ZIP: "Path to the .zip file built for Chrome Web Store upload.",
136
+ FIREFOX_EXTENSION_ID: "The addon GUID ({uuid} format) or email-style ID from your addon's AMO page.",
137
+ FIREFOX_JWT_ISSUER: "API key from https://addons.mozilla.org/developers/addon/api/key/",
138
+ FIREFOX_JWT_SECRET: "API secret generated alongside the JWT issuer on AMO.",
139
+ FIREFOX_ZIP: "Path to the .zip file built for Firefox AMO upload.",
140
+ EDGE_PRODUCT_ID: "Product ID from the Edge Partner Center dashboard.",
141
+ EDGE_CLIENT_ID: "Client ID from the Edge Partner Center API settings.",
142
+ EDGE_API_KEY: "API key (v1.1) from https://partner.microsoft.com/dashboard/microsoftedge/publishapi",
143
+ EDGE_ZIP: "Path to the .zip file built for Edge Partner Center upload."
144
+ };
145
+ function validateConfig(raw) {
146
+ const result = deployConfigSchema.safeParse(raw);
147
+ if (!result.success) {
148
+ const lines = result.error.issues.map((issue)=>{
149
+ const envName = pathToEnvName(issue.path);
150
+ const hint = SETUP_HINTS[envName];
151
+ const base = ` - ${envName}: ${issue.message}`;
152
+ return hint ? `${base}\n ${hint}` : base;
153
+ });
154
+ throw new Error([
155
+ "Missing required config. Set via CLI flags or environment variables:",
156
+ ...lines,
157
+ "",
158
+ "Tip: create a .env.submit file in your project root, or pass --help for all flags."
159
+ ].join("\n"));
160
+ }
161
+ return result.data;
162
+ }
163
+ function envBool(name) {
164
+ const val = process.env[name];
165
+ return null == val ? void 0 : "true" === val;
166
+ }
167
+ function envStr(name) {
168
+ const val = process.env[name];
169
+ return val || void 0;
170
+ }
171
+ function envInt(name) {
172
+ const val = process.env[name];
173
+ return null == val ? void 0 : parseInt(val, 10);
174
+ }
175
+ const promises_namespaceObject = require("node:fs/promises");
176
+ var promises_default = /*#__PURE__*/ __webpack_require__.n(promises_namespaceObject);
177
+ async function fetchJson(url, init) {
178
+ const res = await fetch(url, init);
179
+ if (!res.ok) {
180
+ const body = await res.text().catch(()=>"");
181
+ throw new Error(`HTTP ${res.status} ${res.statusText} \u{2014} ${(null == init ? void 0 : init.method) ?? "GET"} ${url}\n${body}`);
182
+ }
183
+ return res.json();
184
+ }
185
+ async function fetchRaw(url, init) {
186
+ const res = await fetch(url, init);
187
+ if (!res.ok) {
188
+ const body = await res.text().catch(()=>"");
189
+ throw new Error(`HTTP ${res.status} ${res.statusText} \u{2014} ${(null == init ? void 0 : init.method) ?? "GET"} ${url}\n${body}`);
190
+ }
191
+ return res;
192
+ }
193
+ async function assertFilePresent(filePath) {
194
+ try {
195
+ await promises_default().access(filePath);
196
+ } catch {
197
+ throw new Error(`File not found: ${filePath}`);
198
+ }
199
+ }
200
+ async function getFileSize(filePath) {
201
+ const stat = await promises_default().stat(filePath);
202
+ return stat.size;
203
+ }
204
+ function formatBytes(bytes) {
205
+ if (bytes < 1024) return `${bytes} B`;
206
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
207
+ return `${(bytes / 1048576).toFixed(2)} MB`;
208
+ }
209
+ function log(store, message) {
210
+ const tag = `[${store}]`;
211
+ console.log(`${tag} ${message}`);
212
+ }
213
+ function logDryStep(store, step, details) {
214
+ const tag = `[${store}] DRY RUN`;
215
+ console.log(`${tag} \u{2192} ${step}`);
216
+ if (details) {
217
+ for (const [key, value] of Object.entries(details))if (null != value) console.log(`${tag} ${key}: ${value}`);
218
+ }
219
+ }
220
+ const CWS_OAUTH_URL = "https://oauth2.googleapis.com/token";
221
+ const CWS_UPLOAD_BASE = "https://www.googleapis.com/upload/chromewebstore/v1.1/items";
222
+ const CWS_PUBLISH_BASE = "https://www.googleapis.com/chromewebstore/v1.1/items";
223
+ const CWS_ITEMS_BASE = "https://www.googleapis.com/chromewebstore/v1.1/items";
224
+ function chromeStoreUrl(extensionId) {
225
+ return `https://chromewebstore.google.com/detail/${extensionId}`;
226
+ }
227
+ async function authenticate(clientId, clientSecret, refreshToken) {
228
+ return fetchJson(CWS_OAUTH_URL, {
229
+ method: "POST",
230
+ body: JSON.stringify({
231
+ client_id: clientId,
232
+ client_secret: clientSecret,
233
+ refresh_token: refreshToken,
234
+ grant_type: "refresh_token",
235
+ redirect_uri: "urn:ietf:wg:oauth:2.0:oob"
236
+ }),
237
+ headers: {
238
+ "Content-Type": "application/json"
239
+ }
240
+ });
241
+ }
242
+ async function chrome_upload(extensionId, zipPath, token) {
243
+ const body = await promises_default().readFile(zipPath);
244
+ const res = await fetch(`${CWS_UPLOAD_BASE}/${extensionId}`, {
245
+ method: "PUT",
246
+ body,
247
+ headers: {
248
+ Authorization: `${token.token_type} ${token.access_token}`,
249
+ "x-goog-api-version": "2",
250
+ "Content-Type": "application/zip"
251
+ }
252
+ });
253
+ if (!res.ok) {
254
+ const text = await res.text().catch(()=>"");
255
+ throw new Error(`Chrome upload failed: ${res.status} ${res.statusText}\n${text}`);
256
+ }
257
+ }
258
+ async function publish(params) {
259
+ const url = new URL(`${CWS_PUBLISH_BASE}/${params.extensionId}/publish`);
260
+ url.searchParams.set("publishTarget", params.publishTarget);
261
+ if (null != params.deployPercentage) url.searchParams.set("deployPercentage", String(params.deployPercentage));
262
+ if (null != params.reviewExemption) url.searchParams.set("reviewExemption", String(params.reviewExemption));
263
+ const res = await fetch(url.href, {
264
+ method: "POST",
265
+ headers: {
266
+ Authorization: `${params.token.token_type} ${params.token.access_token}`,
267
+ "x-goog-api-version": "2",
268
+ "Content-Length": "0"
269
+ }
270
+ });
271
+ if (!res.ok) {
272
+ const text = await res.text().catch(()=>"");
273
+ throw new Error(`Chrome publish failed: ${res.status} ${res.statusText}\n${text}`);
274
+ }
275
+ }
276
+ async function publishChrome(options, dryRun) {
277
+ await assertFilePresent(options.zip);
278
+ const zipSize = await getFileSize(options.zip);
279
+ log("chrome", "Authenticating with Chrome Web Store");
280
+ const token = await authenticate(options.clientId, options.clientSecret, options.refreshToken);
281
+ const outcome = {
282
+ storeUrl: chromeStoreUrl(options.extensionId),
283
+ submissionId: options.extensionId
284
+ };
285
+ if (dryRun) {
286
+ logDryStep("chrome", "Authentication succeeded", {
287
+ tokenType: token.token_type,
288
+ scope: "chromewebstore"
289
+ });
290
+ logDryStep("chrome", "Would upload ZIP", {
291
+ file: options.zip,
292
+ size: formatBytes(zipSize),
293
+ target: `${CWS_UPLOAD_BASE}/${options.extensionId}`,
294
+ method: "PUT"
295
+ });
296
+ options.skipSubmitReview ? logDryStep("chrome", "Would skip publish (skipSubmitReview=true)") : logDryStep("chrome", "Would publish for review", {
297
+ target: `${CWS_PUBLISH_BASE}/${options.extensionId}/publish`,
298
+ publishTarget: options.publishTarget ?? "default",
299
+ deployPercentage: options.deployPercentage,
300
+ reviewExemption: options.reviewExemption
301
+ });
302
+ log("chrome", "Dry run complete \u2014 no changes made");
303
+ return outcome;
304
+ }
305
+ log("chrome", `Uploading ZIP file (${formatBytes(zipSize)})`);
306
+ await chrome_upload(options.extensionId, options.zip, token);
307
+ if (options.skipSubmitReview) {
308
+ log("chrome", "Skipping publish step (skipSubmitReview=true)");
309
+ return outcome;
310
+ }
311
+ log("chrome", "Publishing extension");
312
+ await publish({
313
+ extensionId: options.extensionId,
314
+ publishTarget: options.publishTarget,
315
+ token,
316
+ deployPercentage: options.deployPercentage,
317
+ reviewExemption: options.reviewExemption
318
+ });
319
+ return outcome;
320
+ }
321
+ async function getChromeItem(params) {
322
+ const token = await authenticate(params.clientId, params.clientSecret, params.refreshToken);
323
+ const url = `${CWS_ITEMS_BASE}/${encodeURIComponent(params.extensionId)}?projection=${params.projection ?? "DRAFT"}`;
324
+ return fetchJson(url, {
325
+ headers: {
326
+ Authorization: `${token.token_type} ${token.access_token}`,
327
+ "x-goog-api-version": "2"
328
+ }
329
+ });
330
+ }
331
+ async function verifyChromeCredentials(params) {
332
+ let token;
333
+ try {
334
+ token = await authenticate(params.clientId, params.clientSecret, params.refreshToken);
335
+ } catch (err) {
336
+ return {
337
+ ok: false,
338
+ message: `OAuth token exchange failed. Verify your Client ID, Client Secret, and Refresh Token are correct.\n${err instanceof Error ? err.message : err}`
339
+ };
340
+ }
341
+ try {
342
+ const item = await fetchJson(`${CWS_ITEMS_BASE}/${encodeURIComponent(params.extensionId)}?projection=DRAFT`, {
343
+ headers: {
344
+ Authorization: `${token.token_type} ${token.access_token}`
345
+ }
346
+ });
347
+ const title = (null == item ? void 0 : item.title) || params.extensionId;
348
+ return {
349
+ ok: true,
350
+ message: `Credentials verified. You have access to "${title}".`,
351
+ extensionTitle: title
352
+ };
353
+ } catch (err) {
354
+ const msg = err instanceof Error ? err.message : String(err);
355
+ if (msg.includes("404")) return {
356
+ ok: false,
357
+ message: "Extension ID not found. Verify the ID is correct and belongs to your account."
358
+ };
359
+ if (msg.includes("403")) return {
360
+ ok: false,
361
+ message: `Access denied to extension ${params.extensionId}. You may not be the owner or a developer on this item.`
362
+ };
363
+ return {
364
+ ok: false,
365
+ message: `Chrome Web Store API check failed: ${msg}`
366
+ };
367
+ }
368
+ }
369
+ const external_node_crypto_namespaceObject = require("node:crypto");
370
+ var external_node_crypto_default = /*#__PURE__*/ __webpack_require__.n(external_node_crypto_namespaceObject);
371
+ function delay(ms) {
372
+ return new Promise((resolve)=>{
373
+ setTimeout(resolve, ms);
374
+ });
375
+ }
376
+ const AMO_BASE = "https://addons.mozilla.org/api/v5/addons";
377
+ const AMO_PROFILE_URL = "https://addons.mozilla.org/api/v5/accounts/profile/";
378
+ const POLL_INTERVAL_MS = 5000;
379
+ const VALIDATION_TIMEOUT_MS = 600000;
380
+ function firefoxStoreUrl(addonIdOrSlug) {
381
+ return `https://addons.mozilla.org/firefox/addon/${addonIdOrSlug}`;
382
+ }
383
+ function signJwt(issuer, secret, expiresInSeconds = 30) {
384
+ const header = {
385
+ alg: "HS256",
386
+ typ: "JWT"
387
+ };
388
+ const now = Math.floor(Date.now() / 1000);
389
+ const payload = {
390
+ iss: issuer,
391
+ jti: Math.random().toString(),
392
+ iat: now,
393
+ exp: now + expiresInSeconds
394
+ };
395
+ const b64 = (obj)=>Buffer.from(JSON.stringify(obj)).toString("base64url");
396
+ const segments = `${b64(header)}.${b64(payload)}`;
397
+ const sig = external_node_crypto_default().createHmac("sha256", secret).update(segments).digest("base64url");
398
+ return `${segments}.${sig}`;
399
+ }
400
+ function authHeaders(jwtIssuer, jwtSecret) {
401
+ return {
402
+ Authorization: `JWT ${signJwt(jwtIssuer, jwtSecret)}`
403
+ };
404
+ }
405
+ function getAddon(addonId, jwtIssuer, jwtSecret) {
406
+ return fetchJson(`${AMO_BASE}/addon/${addonId}`, {
407
+ headers: authHeaders(jwtIssuer, jwtSecret)
408
+ });
409
+ }
410
+ async function createUpload(zipPath, channel, jwtIssuer, jwtSecret) {
411
+ const buf = await promises_default().readFile(zipPath);
412
+ const blob = new Blob([
413
+ buf
414
+ ], {
415
+ type: "application/zip"
416
+ });
417
+ const form = new FormData();
418
+ form.set("channel", channel);
419
+ form.set("upload", blob, "extension.zip");
420
+ return fetchJson(`${AMO_BASE}/upload/`, {
421
+ method: "POST",
422
+ body: form,
423
+ headers: authHeaders(jwtIssuer, jwtSecret)
424
+ });
425
+ }
426
+ function getUpload(uuid, jwtIssuer, jwtSecret) {
427
+ return fetchJson(`${AMO_BASE}/upload/${uuid}`, {
428
+ headers: authHeaders(jwtIssuer, jwtSecret)
429
+ });
430
+ }
431
+ async function createVersion(params) {
432
+ const form = new FormData();
433
+ form.set("upload", params.uploadUuid);
434
+ if (params.sourcesZip) {
435
+ const srcBuf = await promises_default().readFile(params.sourcesZip);
436
+ const srcBlob = new Blob([
437
+ srcBuf
438
+ ], {
439
+ type: "application/zip"
440
+ });
441
+ form.set("source", srcBlob, "sources.zip");
442
+ } else form.set("source", "");
443
+ return fetchJson(`${AMO_BASE}/addon/${params.addonId}/versions/`, {
444
+ method: "POST",
445
+ body: form,
446
+ headers: authHeaders(params.jwtIssuer, params.jwtSecret)
447
+ });
448
+ }
449
+ async function publishFirefox(options, dryRun) {
450
+ await assertFilePresent(options.zip);
451
+ const zipSize = await getFileSize(options.zip);
452
+ let sourcesSize;
453
+ if (options.sourcesZip) {
454
+ await assertFilePresent(options.sourcesZip);
455
+ sourcesSize = await getFileSize(options.sourcesZip);
456
+ }
457
+ const addonId = normalizeAddonId(options.extensionId);
458
+ const { jwtIssuer, jwtSecret } = options;
459
+ log("firefox", "Verifying addon exists");
460
+ await getAddon(addonId, jwtIssuer, jwtSecret);
461
+ const outcome = {
462
+ storeUrl: firefoxStoreUrl(addonId),
463
+ submissionId: addonId
464
+ };
465
+ if (dryRun) {
466
+ logDryStep("firefox", "Addon verified", {
467
+ addonId
468
+ });
469
+ logDryStep("firefox", "Would upload ZIP", {
470
+ file: options.zip,
471
+ size: formatBytes(zipSize),
472
+ channel: options.channel ?? "listed",
473
+ target: `${AMO_BASE}/upload/`,
474
+ method: "POST"
475
+ });
476
+ logDryStep("firefox", "Would poll for validation", {
477
+ interval: `${POLL_INTERVAL_MS / 1000}s`,
478
+ timeout: `${VALIDATION_TIMEOUT_MS / 60000}min`
479
+ });
480
+ logDryStep("firefox", "Would create new version", {
481
+ target: `${AMO_BASE}/addon/${addonId}/versions/`,
482
+ method: "POST",
483
+ sourcesZip: options.sourcesZip ? `${options.sourcesZip} (${formatBytes(sourcesSize)})` : "(none)"
484
+ });
485
+ log("firefox", "Dry run complete \u2014 no changes made");
486
+ return outcome;
487
+ }
488
+ const upload = await uploadAndAwaitProcessing(options, jwtIssuer, jwtSecret);
489
+ outcome.submissionId = upload.uuid;
490
+ log("firefox", "Creating new version");
491
+ const version = await createVersion({
492
+ addonId,
493
+ sourcesZip: options.sourcesZip,
494
+ uploadUuid: upload.uuid,
495
+ jwtIssuer,
496
+ jwtSecret
497
+ });
498
+ outcome.submissionId = String(version.id);
499
+ const { errors, warnings, notices } = upload.validation;
500
+ log("firefox", `Validation: ${errors} error(s), ${warnings} warning(s), ${notices} notice(s)`);
501
+ if (!upload.valid) throw new Error("Firefox extension failed validation");
502
+ return outcome;
503
+ }
504
+ function getFirefoxVersion(params) {
505
+ const normalized = normalizeAddonId(params.addonId);
506
+ return fetchJson(`${AMO_BASE}/addon/${normalized}/versions/${params.versionId}/`, {
507
+ headers: authHeaders(params.jwtIssuer, params.jwtSecret)
508
+ });
509
+ }
510
+ async function uploadAndAwaitProcessing(options, jwtIssuer, jwtSecret) {
511
+ const size = await getFileSize(options.zip);
512
+ log("firefox", `Uploading ZIP file (${formatBytes(size)})`);
513
+ let result = await createUpload(options.zip, options.channel, jwtIssuer, jwtSecret);
514
+ log("firefox", "Waiting for validation");
515
+ const deadline = Date.now() + VALIDATION_TIMEOUT_MS;
516
+ while(!result.processed){
517
+ if (Date.now() > deadline) throw new Error(`Firefox validation timed out after ${VALIDATION_TIMEOUT_MS}ms`);
518
+ await delay(POLL_INTERVAL_MS);
519
+ result = await getUpload(result.uuid, jwtIssuer, jwtSecret);
520
+ }
521
+ return result;
522
+ }
523
+ function normalizeAddonId(id) {
524
+ if (id.startsWith("{") && id.endsWith("}")) return id.slice(1, -1);
525
+ return id;
526
+ }
527
+ async function verifyFirefoxCredentials(params) {
528
+ try {
529
+ const jwt = signJwt(params.jwtIssuer, params.jwtSecret, 60);
530
+ await fetchJson(AMO_PROFILE_URL, {
531
+ headers: {
532
+ Authorization: `JWT ${jwt}`
533
+ }
534
+ });
535
+ } catch (err) {
536
+ return {
537
+ ok: false,
538
+ message: `AMO API credential check failed. Verify your JWT Issuer and Secret are correct.\n${err instanceof Error ? err.message : err}`
539
+ };
540
+ }
541
+ if (params.addonId) {
542
+ const normalizedId = normalizeAddonId(params.addonId);
543
+ try {
544
+ const addon = await getAddon(normalizedId, params.jwtIssuer, params.jwtSecret);
545
+ const name = addon.name ?? params.addonId;
546
+ const displayName = "object" == typeof name && null !== name ? name.en_US ?? params.addonId : String(name);
547
+ return {
548
+ ok: true,
549
+ message: `API credentials and add-on ownership verified. You have access to "${displayName}".`,
550
+ addonName: displayName
551
+ };
552
+ } catch (err) {
553
+ const msg = err instanceof Error ? err.message : String(err);
554
+ if (msg.includes("404")) return {
555
+ ok: false,
556
+ message: "Add-on GUID not found. Verify the GUID is correct in your add-on's Developer Hub page."
557
+ };
558
+ if (msg.includes("403") || msg.includes("401")) return {
559
+ ok: false,
560
+ message: "You don't have permission to access this add-on. Verify you're using credentials for the correct account."
561
+ };
562
+ return {
563
+ ok: false,
564
+ message: `Failed to verify add-on ownership: ${msg}`
565
+ };
566
+ }
567
+ }
568
+ return {
569
+ ok: true,
570
+ message: "API credentials verified. Provide an addon GUID to also verify add-on ownership."
571
+ };
572
+ }
573
+ const EDGE_API_BASE = "https://api.addons.microsoftedge.microsoft.com/v1/products";
574
+ const edge_POLL_INTERVAL_MS = 5000;
575
+ const edge_VALIDATION_TIMEOUT_MS = 600000;
576
+ function edgeStoreUrl(productId) {
577
+ return `https://microsoftedge.microsoft.com/addons/detail/${productId}`;
578
+ }
579
+ function partnerHeaders(clientId, apiKey) {
580
+ return {
581
+ Authorization: `ApiKey ${apiKey}`,
582
+ "X-ClientID": clientId
583
+ };
584
+ }
585
+ async function uploadDraft(productId, zipPath, clientId, apiKey) {
586
+ const body = await promises_default().readFile(zipPath);
587
+ const res = await fetchRaw(`${EDGE_API_BASE}/${productId}/submissions/draft/package`, {
588
+ method: "POST",
589
+ body,
590
+ headers: {
591
+ ...partnerHeaders(clientId, apiKey),
592
+ "Content-Type": "application/zip"
593
+ }
594
+ });
595
+ const operationId = res.headers.get("Location");
596
+ if (!operationId) throw new Error("Edge API did not return an operation ID in the Location header.");
597
+ return operationId;
598
+ }
599
+ function getDraftOperation(productId, operationId, clientId, apiKey) {
600
+ return fetchJson(`${EDGE_API_BASE}/${productId}/submissions/draft/package/operations/${operationId}`, {
601
+ headers: partnerHeaders(clientId, apiKey)
602
+ });
603
+ }
604
+ async function submitForReview(productId, clientId, apiKey) {
605
+ const res = await fetchRaw(`${EDGE_API_BASE}/${productId}/submissions`, {
606
+ method: "POST",
607
+ body: JSON.stringify({}),
608
+ headers: {
609
+ ...partnerHeaders(clientId, apiKey),
610
+ "Content-Type": "application/json"
611
+ }
612
+ });
613
+ const location = res.headers.get("Location");
614
+ if (!location) return;
615
+ const segments = location.split("/").filter(Boolean);
616
+ return segments[segments.length - 1];
617
+ }
618
+ async function publishEdge(options, dryRun) {
619
+ await assertFilePresent(options.zip);
620
+ const zipSize = await getFileSize(options.zip);
621
+ const outcome = {
622
+ storeUrl: edgeStoreUrl(options.productId),
623
+ submissionId: options.productId
624
+ };
625
+ if (dryRun) {
626
+ logDryStep("edge", "Credentials assumed valid (no preflight endpoint)", {
627
+ productId: options.productId,
628
+ clientId: options.clientId
629
+ });
630
+ logDryStep("edge", "Would upload draft ZIP", {
631
+ file: options.zip,
632
+ size: formatBytes(zipSize),
633
+ target: `${EDGE_API_BASE}/${options.productId}/submissions/draft/package`,
634
+ method: "POST"
635
+ });
636
+ logDryStep("edge", "Would poll draft operation", {
637
+ interval: `${edge_POLL_INTERVAL_MS / 1000}s`,
638
+ timeout: `${edge_VALIDATION_TIMEOUT_MS / 60000}min`
639
+ });
640
+ options.skipSubmitReview ? logDryStep("edge", "Would skip submit (skipSubmitReview=true)") : logDryStep("edge", "Would submit for review", {
641
+ target: `${EDGE_API_BASE}/${options.productId}/submissions`,
642
+ method: "POST"
643
+ });
644
+ log("edge", "Dry run complete \u2014 no changes made");
645
+ return outcome;
646
+ }
647
+ const uploadOperationId = await edge_uploadAndAwaitProcessing(options);
648
+ outcome.submissionId = uploadOperationId;
649
+ if (options.skipSubmitReview) {
650
+ log("edge", "Skipping publish step (skipSubmitReview=true)");
651
+ return outcome;
652
+ }
653
+ log("edge", "Submitting for review");
654
+ const publishOperationId = await submitForReview(options.productId, options.clientId, options.apiKey);
655
+ if (publishOperationId) outcome.submissionId = publishOperationId;
656
+ return outcome;
657
+ }
658
+ function getEdgePublishOperation(params) {
659
+ return fetchJson(`${EDGE_API_BASE}/${params.productId}/submissions/operations/${params.operationId}`, {
660
+ headers: partnerHeaders(params.clientId, params.apiKey)
661
+ });
662
+ }
663
+ async function verifyEdgeCredentials(params) {
664
+ const headers = partnerHeaders(params.clientId, params.apiKey);
665
+ if (!params.productId) {
666
+ const res = await fetch(EDGE_API_BASE, {
667
+ headers
668
+ });
669
+ if (401 === res.status || 403 === res.status) return {
670
+ ok: false,
671
+ message: "Invalid credentials. Verify your Client ID and API Key are correct."
672
+ };
673
+ if (!res.ok) return {
674
+ ok: false,
675
+ message: `Edge Partner API check failed (HTTP ${res.status}).`
676
+ };
677
+ return {
678
+ ok: true,
679
+ message: "Credentials verified. Provide a Product ID to also verify extension ownership."
680
+ };
681
+ }
682
+ const res = await fetch(`${EDGE_API_BASE}/${encodeURIComponent(params.productId)}/submissions/draft`, {
683
+ headers
684
+ });
685
+ if (401 === res.status) return {
686
+ ok: false,
687
+ message: "Unauthorized. Verify your API credentials are correct."
688
+ };
689
+ if (403 === res.status) {
690
+ const body = await res.text().catch(()=>"");
691
+ if (/product not found|not found/i.test(body)) return {
692
+ ok: false,
693
+ message: "Product ID not found or not owned by this account. Verify the GUID matches your Partner Center extension."
694
+ };
695
+ return {
696
+ ok: false,
697
+ message: "Invalid credentials. Verify your Client ID and API Key are correct."
698
+ };
699
+ }
700
+ if (200 === res.status) return {
701
+ ok: true,
702
+ message: "Credentials and Product ID verified. Draft submission exists."
703
+ };
704
+ if (404 === res.status) return {
705
+ ok: true,
706
+ message: "Credentials and Product ID verified. Ready to submit."
707
+ };
708
+ return {
709
+ ok: false,
710
+ message: `Edge Partner API check failed (HTTP ${res.status}).`
711
+ };
712
+ }
713
+ async function edge_uploadAndAwaitProcessing(options) {
714
+ const size = await getFileSize(options.zip);
715
+ log("edge", `Uploading ZIP file (${formatBytes(size)})`);
716
+ const operationId = await uploadDraft(options.productId, options.zip, options.clientId, options.apiKey);
717
+ log("edge", "Waiting for validation");
718
+ const deadline = Date.now() + edge_VALIDATION_TIMEOUT_MS;
719
+ let operation;
720
+ do {
721
+ if (Date.now() > deadline) throw new Error(`Edge validation timed out after ${edge_VALIDATION_TIMEOUT_MS}ms`);
722
+ await delay(edge_POLL_INTERVAL_MS);
723
+ operation = await getDraftOperation(options.productId, operationId, options.clientId, options.apiKey);
724
+ }while ("InProgress" === operation.status);
725
+ if ("Failed" === operation.status) throw new Error(`Edge validation failed: ${JSON.stringify(operation, null, 2)}`);
726
+ log("edge", "Extension is valid");
727
+ return operationId;
728
+ }
729
+ async function deploy(config) {
730
+ const validated = validateConfig(config);
731
+ const { dryRun } = validated;
732
+ const jobs = [];
733
+ if (validated.chrome) {
734
+ const opts = validated.chrome;
735
+ jobs.push({
736
+ key: "chrome",
737
+ run: ()=>publishChrome(opts, dryRun)
738
+ });
739
+ }
740
+ if (validated.firefox) {
741
+ const opts = validated.firefox;
742
+ jobs.push({
743
+ key: "firefox",
744
+ run: ()=>publishFirefox(opts, dryRun)
745
+ });
746
+ }
747
+ if (validated.edge) {
748
+ const opts = validated.edge;
749
+ jobs.push({
750
+ key: "edge",
751
+ run: ()=>publishEdge(opts, dryRun)
752
+ });
753
+ }
754
+ if (0 === jobs.length) throw new Error("No stores configured. Provide at least one store to deploy to.\n\nEach store is activated by providing its ZIP path:\n Chrome: --chrome-zip <path> or CHROME_ZIP=<path>\n Firefox: --firefox-zip <path> or FIREFOX_ZIP=<path>\n Edge: --edge-zip <path> or EDGE_ZIP=<path>\n\nRun extension-deploy --help for all options, or create a .env.submit file.");
755
+ if (dryRun) console.log("\n[deploy] Dry run enabled \u2014 will verify auth without uploading\n");
756
+ else console.log("\n[deploy] Deploying extension\n");
757
+ const settled = await Promise.allSettled(jobs.map(async ({ key, run })=>{
758
+ const start = Date.now();
759
+ try {
760
+ const outcome = await run();
761
+ return {
762
+ store: key,
763
+ success: true,
764
+ status: dryRun ? "dry_run" : "submitted",
765
+ duration: Date.now() - start,
766
+ storeUrl: outcome.storeUrl,
767
+ submissionId: outcome.submissionId
768
+ };
769
+ } catch (err) {
770
+ return {
771
+ store: key,
772
+ success: false,
773
+ status: "failed",
774
+ error: err instanceof Error ? err.message : String(err),
775
+ duration: Date.now() - start
776
+ };
777
+ }
778
+ }));
779
+ const stores = settled.map((s, i)=>"fulfilled" === s.status ? s.value : {
780
+ store: jobs[i].key,
781
+ success: false,
782
+ status: "failed",
783
+ error: s.reason instanceof Error ? s.reason.message : String(s.reason),
784
+ duration: 0
785
+ });
786
+ const success = stores.every((s)=>s.success);
787
+ console.log("\n--- Deploy Summary ---");
788
+ for (const s of stores){
789
+ const icon = s.success ? "OK" : "FAIL";
790
+ console.log(` ${icon} ${s.store} (${s.status}, ${s.duration}ms)`);
791
+ if (s.error) console.error(` ${s.error}`);
792
+ }
793
+ console.log("");
794
+ return {
795
+ dryRun,
796
+ stores,
797
+ success
798
+ };
799
+ }
800
+ const DEFAULT_POLL_INTERVAL_MS = 60000;
801
+ const DEFAULT_TIMEOUT_MS = 3600000;
802
+ function watch_now() {
803
+ return new Date().toISOString();
804
+ }
805
+ function isTerminal(status) {
806
+ return "published" === status || "rejected" === status || "failed" === status;
807
+ }
808
+ async function getChromeSubmissionEvent(input) {
809
+ try {
810
+ const item = await getChromeItem(input);
811
+ const uploadState = item.uploadState;
812
+ let status = "unknown";
813
+ let message;
814
+ if ("SUCCESS" === uploadState) {
815
+ status = "in_review";
816
+ message = "Upload accepted by the Chrome Web Store. Review state is not exposed via API; check the developer dashboard for final outcome.";
817
+ } else if ("IN_PROGRESS" === uploadState) status = "processing";
818
+ else if ("FAILURE" === uploadState) {
819
+ var _item_itemError;
820
+ status = "failed";
821
+ message = (null == (_item_itemError = item.itemError) ? void 0 : _item_itemError.map((e)=>e.error_detail).join("; ")) ?? "Upload reported FAILURE by Chrome Web Store.";
822
+ }
823
+ return {
824
+ store: "chrome",
825
+ status,
826
+ nativeStatus: uploadState,
827
+ message,
828
+ polledAt: watch_now(),
829
+ submissionId: input.extensionId,
830
+ storeUrl: chromeStoreUrl(input.extensionId)
831
+ };
832
+ } catch (err) {
833
+ return {
834
+ store: "chrome",
835
+ status: "failed",
836
+ message: err instanceof Error ? err.message : String(err),
837
+ polledAt: watch_now(),
838
+ submissionId: input.extensionId,
839
+ storeUrl: chromeStoreUrl(input.extensionId)
840
+ };
841
+ }
842
+ }
843
+ function watchChromeSubmission(input, options = {}) {
844
+ return runWatchLoop("chrome", ()=>getChromeSubmissionEvent(input), options);
845
+ }
846
+ function mapEdgeStatus(native) {
847
+ switch(native){
848
+ case "Succeeded":
849
+ return "published";
850
+ case "Failed":
851
+ return "failed";
852
+ case "InProgress":
853
+ default:
854
+ return "in_review";
855
+ }
856
+ }
857
+ async function getEdgeSubmissionEvent(input) {
858
+ try {
859
+ const op = await getEdgePublishOperation({
860
+ productId: input.productId,
861
+ operationId: input.operationId,
862
+ clientId: input.clientId,
863
+ apiKey: input.apiKey
864
+ });
865
+ return {
866
+ store: "edge",
867
+ status: mapEdgeStatus(op.status),
868
+ nativeStatus: op.status,
869
+ message: op.message ?? void 0,
870
+ polledAt: watch_now(),
871
+ submissionId: input.operationId,
872
+ storeUrl: edgeStoreUrl(input.productId)
873
+ };
874
+ } catch (err) {
875
+ return {
876
+ store: "edge",
877
+ status: "failed",
878
+ message: err instanceof Error ? err.message : String(err),
879
+ polledAt: watch_now(),
880
+ submissionId: input.operationId,
881
+ storeUrl: edgeStoreUrl(input.productId)
882
+ };
883
+ }
884
+ }
885
+ function watchEdgeSubmission(input, options = {}) {
886
+ return runWatchLoop("edge", ()=>getEdgeSubmissionEvent(input), options);
887
+ }
888
+ function mapFirefoxFileStatus(native) {
889
+ if (!native) return "unknown";
890
+ if ("public" === native) return "published";
891
+ if ("unreviewed" === native) return "in_review";
892
+ if ("disabled" === native) return "rejected";
893
+ return "unknown";
894
+ }
895
+ async function getFirefoxSubmissionEvent(input) {
896
+ try {
897
+ const version = await getFirefoxVersion({
898
+ addonId: input.extensionId,
899
+ versionId: input.versionId,
900
+ jwtIssuer: input.jwtIssuer,
901
+ jwtSecret: input.jwtSecret
902
+ });
903
+ const fileStatus = version.file.status;
904
+ return {
905
+ store: "firefox",
906
+ status: mapFirefoxFileStatus(fileStatus),
907
+ nativeStatus: fileStatus,
908
+ polledAt: watch_now(),
909
+ submissionId: String(version.id),
910
+ storeUrl: firefoxStoreUrl(input.extensionId)
911
+ };
912
+ } catch (err) {
913
+ return {
914
+ store: "firefox",
915
+ status: "failed",
916
+ message: err instanceof Error ? err.message : String(err),
917
+ polledAt: watch_now(),
918
+ submissionId: String(input.versionId),
919
+ storeUrl: firefoxStoreUrl(input.extensionId)
920
+ };
921
+ }
922
+ }
923
+ function watchFirefoxSubmission(input, options = {}) {
924
+ return runWatchLoop("firefox", ()=>getFirefoxSubmissionEvent(input), options);
925
+ }
926
+ async function runWatchLoop(_store, probe, options) {
927
+ const pollInterval = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
928
+ const timeout = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
929
+ const deadline = Date.now() + timeout;
930
+ let lastEvent;
931
+ while(true){
932
+ var _options_onEvent;
933
+ lastEvent = await probe();
934
+ null == (_options_onEvent = options.onEvent) || _options_onEvent.call(options, lastEvent);
935
+ if (isTerminal(lastEvent.status)) return lastEvent;
936
+ if (Date.now() >= deadline) return lastEvent;
937
+ await delay(pollInterval);
938
+ }
939
+ }
940
+ exports.chromeOptionsSchema = __webpack_exports__.chromeOptionsSchema;
941
+ exports.deploy = __webpack_exports__.deploy;
942
+ exports.deployConfigSchema = __webpack_exports__.deployConfigSchema;
943
+ exports.edgeOptionsSchema = __webpack_exports__.edgeOptionsSchema;
944
+ exports.firefoxOptionsSchema = __webpack_exports__.firefoxOptionsSchema;
945
+ exports.getChromeSubmissionEvent = __webpack_exports__.getChromeSubmissionEvent;
946
+ exports.getEdgeSubmissionEvent = __webpack_exports__.getEdgeSubmissionEvent;
947
+ exports.getFirefoxSubmissionEvent = __webpack_exports__.getFirefoxSubmissionEvent;
948
+ exports.resolveConfig = __webpack_exports__.resolveConfig;
949
+ exports.validateConfig = __webpack_exports__.validateConfig;
950
+ exports.verifyChromeCredentials = __webpack_exports__.verifyChromeCredentials;
951
+ exports.verifyEdgeCredentials = __webpack_exports__.verifyEdgeCredentials;
952
+ exports.verifyFirefoxCredentials = __webpack_exports__.verifyFirefoxCredentials;
953
+ exports.watchChromeSubmission = __webpack_exports__.watchChromeSubmission;
954
+ exports.watchEdgeSubmission = __webpack_exports__.watchEdgeSubmission;
955
+ exports.watchFirefoxSubmission = __webpack_exports__.watchFirefoxSubmission;
956
+ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
957
+ "chromeOptionsSchema",
958
+ "deploy",
959
+ "deployConfigSchema",
960
+ "edgeOptionsSchema",
961
+ "firefoxOptionsSchema",
962
+ "getChromeSubmissionEvent",
963
+ "getEdgeSubmissionEvent",
964
+ "getFirefoxSubmissionEvent",
965
+ "resolveConfig",
966
+ "validateConfig",
967
+ "verifyChromeCredentials",
968
+ "verifyEdgeCredentials",
969
+ "verifyFirefoxCredentials",
970
+ "watchChromeSubmission",
971
+ "watchEdgeSubmission",
972
+ "watchFirefoxSubmission"
973
+ ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
974
+ Object.defineProperty(exports, '__esModule', {
975
+ value: true
976
+ });