Skip to content

Commit f413395

Browse files
committed
fix: resolve Chrome Web Store API V2 403 error
- Fix publish endpoint from /publish to :publish in service account script - Add CRX/ZIP detection with appropriate content-type handling - Enhance service account key parsing with validation and logging - Improve error handling for authentication failures This resolves the PERMISSION_DENIED 403 error by using correct API endpoints and proper file format handling for Chrome Web Store deployment.
1 parent 92e8b0a commit f413395

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "blog-link-analyzer",
3-
"version": "1.6.7",
3+
"version": "1.6.8",
44
"description": "Detects blog posts and extracts linked blog content with titles and authors",
55
"main": "background/service-worker.js",
66
"scripts": {

scripts/deploy-chrome-simple.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,24 @@ try {
3333
// Use Google Auth Library for proper JWT handling
3434
console.log('🔐 Getting access token using Google Auth Library...');
3535

36+
// Parse and validate service account key
37+
let serviceAccountData;
38+
try {
39+
serviceAccountData = JSON.parse(config.serviceAccountKey);
40+
console.log('✅ Service account key parsed successfully');
41+
console.log(` Service account: ${serviceAccountData.client_email}`);
42+
} catch (error) {
43+
console.error('❌ Failed to parse service account key:', error.message);
44+
throw new Error('Invalid service account key format');
45+
}
46+
3647
const { GoogleAuth } = await import('google-auth-library');
3748

3849
const auth = new GoogleAuth({
3950
scopes: ['https://www.googleapis.com/auth/chromewebstore'],
4051
credentials: {
41-
client_email: JSON.parse(config.serviceAccountKey).client_email,
42-
private_key: JSON.parse(config.serviceAccountKey).private_key,
52+
client_email: serviceAccountData.client_email,
53+
private_key: serviceAccountData.private_key,
4354
}
4455
});
4556

@@ -48,21 +59,34 @@ try {
4859

4960
console.log('✅ Access token obtained successfully');
5061

51-
// Read ZIP file
52-
const zipData = fs.readFileSync(config.zipPath);
62+
// Check if we should use CRX or ZIP format
63+
const crxPath = config.zipPath.replace('.zip', '.crx');
64+
let uploadData, contentType, uploadType;
65+
66+
if (fs.existsSync(crxPath)) {
67+
console.log('📦 Using CRX file for upload (Chrome Web Store preferred format)');
68+
uploadData = fs.readFileSync(crxPath);
69+
contentType = 'application/x-chrome-extension';
70+
uploadType = 'CRX';
71+
} else {
72+
console.log('📦 Using ZIP file for upload');
73+
uploadData = fs.readFileSync(config.zipPath);
74+
contentType = 'application/zip';
75+
uploadType = 'ZIP';
76+
}
5377

5478
// Upload extension using Chrome Web Store API V2 (correct service account endpoints)
55-
console.log('📤 Uploading extension...');
79+
console.log(`📤 Uploading extension (${uploadType} format)...`);
5680

5781
// First, initiate upload with V2 API
5882
const uploadResponse = await fetch(`https://chromewebstore.googleapis.com/upload/v2/publishers/${config.publisherId}/items/${config.extensionId}:upload`, {
5983
method: 'POST',
6084
headers: {
6185
'Authorization': `Bearer ${accessToken}`,
62-
'Content-Type': 'application/zip',
86+
'Content-Type': contentType,
6387
'x-goog-upload-protocol': 'raw'
6488
},
65-
body: zipData
89+
body: uploadData
6690
});
6791

6892
if (!uploadResponse.ok) {
@@ -77,7 +101,7 @@ try {
77101
// Publish extension using V2 API
78102
console.log('🚀 Publishing extension...');
79103

80-
const publishResponse = await fetch(`https://chromewebstore.googleapis.com/v2/publishers/${config.publisherId}/items/${config.extensionId}/publish`, {
104+
const publishResponse = await fetch(`https://chromewebstore.googleapis.com/v2/publishers/${config.publisherId}/items/${config.extensionId}:publish`, {
81105
method: 'POST',
82106
headers: {
83107
'Authorization': `Bearer ${accessToken}`,

0 commit comments

Comments
 (0)