browser-extension-manager 1.3.13 → 1.3.14
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/CLAUDE.md +26 -1
- package/dist/gulp/tasks/html.js +9 -0
- package/dist/gulp/tasks/publish.js +63 -29
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -209,8 +209,33 @@ When adding a new component type to the framework:
|
|
|
209
209
|
- **distribute** ([gulp/tasks/distribute.js](src/gulp/tasks/distribute.js)) - Copies project files to `dist/`
|
|
210
210
|
- **sass** ([gulp/tasks/sass.js](src/gulp/tasks/sass.js)) - Compiles SCSS with sophisticated load path system
|
|
211
211
|
- **webpack** ([gulp/tasks/webpack.js](src/gulp/tasks/webpack.js)) - Bundles JavaScript with Babel
|
|
212
|
-
- **html** ([gulp/tasks/html.js](src/gulp/tasks/html.js)) - Processes HTML views into templates
|
|
212
|
+
- **html** ([gulp/tasks/html.js](src/gulp/tasks/html.js)) - Processes HTML views into templates (see HTML Templating below)
|
|
213
213
|
- **package** ([gulp/tasks/package.js](src/gulp/tasks/package.js)) - Creates packaged extension
|
|
214
|
+
|
|
215
|
+
### HTML Templating
|
|
216
|
+
|
|
217
|
+
HTML views in `src/views/` are processed through a two-step templating system using `{{ }}` brackets.
|
|
218
|
+
|
|
219
|
+
**Available variables:**
|
|
220
|
+
- `{{ brand.name }}` - Brand name from config
|
|
221
|
+
- `{{ brand.url }}` - Brand URL from config
|
|
222
|
+
- `{{ page.name }}` - Component name (e.g., `popup`, `pages/index`)
|
|
223
|
+
- `{{ page.path }}` - Full view path
|
|
224
|
+
- `{{ page.title }}` - Page title (defaults to brand name)
|
|
225
|
+
- `{{ theme.appearance }}` - Theme appearance (`dark` or `light`)
|
|
226
|
+
- `{{ cacheBust }}` - Cache-busting timestamp
|
|
227
|
+
|
|
228
|
+
**Example usage in views:**
|
|
229
|
+
```html
|
|
230
|
+
<a href="{{ brand.url }}/pricing">Upgrade to Premium</a>
|
|
231
|
+
<p>Welcome to {{ brand.name }}</p>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**How it works:**
|
|
235
|
+
1. Your view file (`src/views/[component]/index.html`) is templated first
|
|
236
|
+
2. The result is injected into [page-template.html](src/config/page-template.html)
|
|
237
|
+
3. The outer template is processed with the same variables
|
|
238
|
+
|
|
214
239
|
- **serve** ([gulp/tasks/serve.js](src/gulp/tasks/serve.js)) - WebSocket server for live reload
|
|
215
240
|
|
|
216
241
|
### Modifying Themes
|
package/dist/gulp/tasks/html.js
CHANGED
|
@@ -105,6 +105,15 @@ function processHtml(templateContent) {
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
// Apply template with custom brackets
|
|
108
|
+
// First, template the body content to replace any {{ }} placeholders in the view
|
|
109
|
+
const templatedBody = template(bodyContent, data, {
|
|
110
|
+
brackets: ['{{', '}}'],
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Update data with templated body
|
|
114
|
+
data.content = templatedBody;
|
|
115
|
+
|
|
116
|
+
// Then template the outer page template
|
|
108
117
|
const rendered = template(templateContent, data, {
|
|
109
118
|
brackets: ['{{', '}}'],
|
|
110
119
|
});
|
|
@@ -314,59 +314,77 @@ async function publishToEdge() {
|
|
|
314
314
|
throw new Error('Missing Edge credentials. Set EDGE_PRODUCT_ID, EDGE_CLIENT_ID, EDGE_API_KEY in .env');
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
317
|
+
// Helper for Edge API requests
|
|
318
|
+
const edgeHeaders = {
|
|
319
|
+
'Authorization': `ApiKey ${apiKey}`,
|
|
320
|
+
'X-ClientID': clientId,
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// Step 1: Try to submit first to check if there's a pending submission
|
|
324
|
+
// This is faster than uploading first, since upload always succeeds
|
|
325
|
+
logger.log('[edge] Checking for pending submissions...');
|
|
326
|
+
|
|
327
|
+
const publishUrl = `https://api.addons.microsoftedge.microsoft.com/v1/products/${productId}/submissions`;
|
|
328
|
+
const checkResponse = await fetch(publishUrl, {
|
|
329
|
+
method: 'POST',
|
|
322
330
|
headers: {
|
|
323
|
-
|
|
324
|
-
'
|
|
331
|
+
...edgeHeaders,
|
|
332
|
+
'Content-Type': 'application/json',
|
|
325
333
|
},
|
|
334
|
+
body: JSON.stringify({
|
|
335
|
+
notes: `Check for pending submission`,
|
|
336
|
+
}),
|
|
326
337
|
});
|
|
327
338
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
339
|
+
const checkData = await checkResponse.json().catch(() => null);
|
|
340
|
+
|
|
341
|
+
// Log the response for debugging
|
|
342
|
+
logger.log(`[edge] Submission check response: ${JSON.stringify(checkData)}`);
|
|
343
|
+
|
|
344
|
+
// Check if there's a pending submission blocking us
|
|
345
|
+
if (checkData && checkData.status === 'Failed') {
|
|
346
|
+
if (checkData.errorCode === 'InProgressSubmission') {
|
|
347
|
+
throw new Error('Extension already has a pending submission in review. Wait for it to complete before publishing again.');
|
|
348
|
+
}
|
|
349
|
+
if (checkData.errorCode === 'UnpublishInProgress') {
|
|
350
|
+
throw new Error('Extension is being unpublished. Wait for unpublish to complete before publishing.');
|
|
351
|
+
}
|
|
352
|
+
// If it failed for another reason (like no draft package), that's expected - continue to upload
|
|
353
|
+
if (checkData.errorCode !== 'NoDraftPackage' && checkData.errorCode !== 'NoPackageToPublish') {
|
|
354
|
+
logger.log(`[edge] Check failed with: ${checkData.errorCode} - ${checkData.message}`);
|
|
334
355
|
}
|
|
335
356
|
}
|
|
336
357
|
|
|
358
|
+
// Step 2: Upload the package
|
|
337
359
|
logger.log('[edge] Uploading to Microsoft Edge Add-ons...');
|
|
338
360
|
|
|
339
|
-
// Read chromium zip file (Edge uses same build as Chrome)
|
|
340
361
|
const zipBuffer = jetpack.read(PATHS.chromium.zip, 'buffer');
|
|
341
|
-
|
|
342
|
-
// Edge API v1.1 endpoint
|
|
343
362
|
const uploadUrl = `https://api.addons.microsoftedge.microsoft.com/v1/products/${productId}/submissions/draft/package`;
|
|
344
363
|
|
|
345
|
-
|
|
346
|
-
const response = await fetch(uploadUrl, {
|
|
364
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
347
365
|
method: 'POST',
|
|
348
366
|
headers: {
|
|
349
|
-
|
|
350
|
-
'X-ClientID': clientId,
|
|
367
|
+
...edgeHeaders,
|
|
351
368
|
'Content-Type': 'application/zip',
|
|
352
369
|
},
|
|
353
370
|
body: zipBuffer,
|
|
354
371
|
});
|
|
355
372
|
|
|
356
|
-
if (!
|
|
357
|
-
const errorText = await
|
|
358
|
-
throw new Error(`Edge
|
|
373
|
+
if (!uploadResponse.ok) {
|
|
374
|
+
const errorText = await uploadResponse.text();
|
|
375
|
+
throw new Error(`Edge upload error: ${uploadResponse.status} - ${errorText}`);
|
|
359
376
|
}
|
|
360
377
|
|
|
378
|
+
const uploadData = await uploadResponse.json().catch(() => null);
|
|
379
|
+
logger.log(`[edge] Upload response: ${JSON.stringify(uploadData)}`);
|
|
380
|
+
|
|
361
381
|
logger.log('[edge] Package uploaded, submitting for review...');
|
|
362
382
|
|
|
363
|
-
// Submit for review
|
|
364
|
-
const publishUrl = `https://api.addons.microsoftedge.microsoft.com/v1/products/${productId}/submissions`;
|
|
383
|
+
// Step 3: Submit for review
|
|
365
384
|
const publishResponse = await fetch(publishUrl, {
|
|
366
385
|
method: 'POST',
|
|
367
386
|
headers: {
|
|
368
|
-
|
|
369
|
-
'X-ClientID': clientId,
|
|
387
|
+
...edgeHeaders,
|
|
370
388
|
'Content-Type': 'application/json',
|
|
371
389
|
},
|
|
372
390
|
body: JSON.stringify({
|
|
@@ -374,9 +392,25 @@ async function publishToEdge() {
|
|
|
374
392
|
}),
|
|
375
393
|
});
|
|
376
394
|
|
|
395
|
+
const publishData = await publishResponse.json().catch(() => null);
|
|
396
|
+
|
|
397
|
+
// Log the full response
|
|
398
|
+
logger.log(`[edge] Publish response: ${JSON.stringify(publishData)}`);
|
|
399
|
+
|
|
400
|
+
// Check for HTTP errors
|
|
377
401
|
if (!publishResponse.ok) {
|
|
378
|
-
|
|
379
|
-
|
|
402
|
+
throw new Error(`Edge publish error: ${publishResponse.status} - ${JSON.stringify(publishData)}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Check for API-level failures (HTTP 200 but status: "Failed")
|
|
406
|
+
if (publishData && publishData.status === 'Failed') {
|
|
407
|
+
if (publishData.errorCode === 'InProgressSubmission') {
|
|
408
|
+
throw new Error('Extension already has a pending submission in review. Wait for it to complete before publishing again.');
|
|
409
|
+
}
|
|
410
|
+
if (publishData.errorCode === 'UnpublishInProgress') {
|
|
411
|
+
throw new Error('Extension is being unpublished. Wait for unpublish to complete before publishing.');
|
|
412
|
+
}
|
|
413
|
+
throw new Error(`Edge publish failed: ${publishData.message || publishData.errorCode || 'Unknown error'}`);
|
|
380
414
|
}
|
|
381
415
|
|
|
382
416
|
logger.log('[edge] Upload complete');
|