Я пытаюсь автоматически опубликовать свой пакет в npm, используя JavaScript SDK npmlibpublish. Вот мой код:
const path = "dist";
const manifest = await pacote.manifest(path);
const tarData = await pacote.tarball(path);
// @ts-ignore
await publish(manifest, tarData, {
npmVersion: `universal-fs@${currentVersion}`,
token: process.env.NPM_TOKEN,
defaultTag: baseBranch === "main" ? "latest" : "canary",
});
Этот код будет запущен в CI. Все переменные окружения корректны, а также manifest
и tarball. Однако, когда я выполняю код, я получаю ошибку:
429 Слишком много запросов - PUT https://registry.npmjs.org/dist
{
headers: [Object: null prototype] {
date: [ 'Вт, 17 Сен 2024 01:46:11 GMT' ],
'content-type': [ 'text/html; charset=UTF-8' ],
'content-length': [ '5399' ],
connection: [ 'keep-alive' ],
'retry-after': [ '3600' ],
'x-frame-options': [ 'SAMEORIGIN' ],
'referrer-policy': [ 'same-origin' ],
'cache-control': [
'private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
],
expires: [ 'Чт, 01 Янв 1970 00:00:01 GMT' ],
vary: [ 'Accept-Encoding' ],
server: [ 'cloudflare' ],
'cf-ray': [ '8c456bccdd722b8e-LAX' ],
'x-fetch-attempts': [ '1' ]
},
statusCode: 429,
code: 'E429',
method: 'PUT',
uri: 'https://registry.npmjs.org/dist',
body: Buffer(5399) [Uint8Array] [
60, 33, 68, 79, 67, 84, 89, 80, 69, 32, 104, 116,
109, 108, 62, 10, 60, 33, 45, 45, 91, 105, 102, 32,
108, 116, 73, 69, 32, 55, 93, 62, 32, 60, 104,
116, 109, 108, 32, 99, 108, 97, 115, 115, 61, 34, 110,
111, 45, 106, 115, 32, 105, 101, 54, 32, 111, 108, 100,
105, 101, 34, 32, 108, 97, 110, 103, 61, 34, 101, 110,
45, 85, 83, 34, 62, 32, 60, 33, 91, 101, 110, 100,
105, 102, 93, 45, 45, 62, 10, 60, 33, 45, 45, 91,
105, 102, 32, 73,
... 5299 more items
],
pkgid: '[email protected]'
}
Что мне показалось странным, так это то, что он пытался опубликовать пакет с названием dist, как видно из pkgid: '[email protected]'
. Однако мой пакет называется universal-fs, и я публикую его из директории dist
.
У меня включена двухфакторная аутентификация на моем аккаунте. name
также определено в моем package.json
. Почему он пытается опубликовать по адресу [email protected]
и почему статус-код 429
? Как я могу это исправить?
Ответ
Проблема, с которой вы столкнулись, связана с ошибкой 429 (Слишком много запросов) при попытке публикации пакета в NPM. Также вы заметили, что ваш пакет пытается опубликоваться под именем dist
, что не соответствует ожидаемому имени вашего пакета (universal-fs
). Давайте разберем причины и предложим решения.
Причины проблемы
-
Ошибка 429 (Слишком много запросов):
- Эта ошибка возникает, когда вы превышаете лимиты на отправку запросов к API NPM. Обычно NPM накладывает ограничения на количество запросов, чтобы предотвратить злоупотребления и обеспечить стабильность сервиса. В вашем случае, судя по сообщениям, NPM сообщает, что вы отправили слишком много запросов за короткий промежуток времени, и советует подождать (в данном случае 3600 секунд, или 1 час).
- Попытка публикации под именем
dist
:- Судя по вашему коду, проблема может возникать из-за того, что функция
publish
неправильно считываетname
из вашего манифеста. Убедитесь, что в вашемpackage.json
правильно указано имя пакета и что оно соответствует тому, что вы ожидаете (в данном случае,universal-fs
).
- Судя по вашему коду, проблема может возникать из-за того, что функция
Возможные решения
-
Обработка ошибки 429:
- Вы можете реализовать стратегию повторной попытки (retry) для обработки ошибок 429. Это можно сделать, например, с помощью временной задержки между повторными попытками.
-
Пример кода с обработкой:
const publishWithRetry = async (manifest, tarData) => { const maxRetries = 5; let attempt = 0; while (attempt < maxRetries) { try { await publish(manifest, tarData, { npmVersion: `universal-fs@${currentVersion}`, token: process.env.NPM_TOKEN, defaultTag: baseBranch === "main" ? "latest" : "canary", }); return; // Успех, выходим из функции } catch (error) { if (error.code === 'E429') { attempt++; const retryAfter = error.headers['retry-after'] ? parseInt(error.headers['retry-after']) * 1000 : 1000; // по умолчанию 1 секунда console.log(`Attempt ${attempt} failed. Retrying in ${retryAfter / 1000} seconds...`); await new Promise(resolve => setTimeout(resolve, retryAfter)); // Ожидание перед повторной попыткой } else { throw error; // Если ошибка не 429, выбрасываем ее } } } throw new Error('Maximum retries exceeded'); };
-
Проверьте ваш
package.json
:-
Убедитесь, что имя вашего пакета в
package.json
правильно указано. Например:{ "name": "universal-fs", "version": "1.0.0", ... }
-
- Долгосрочные решения:
- Оцените частоту ваших публикаций. Возможно, имеет смысл добавить дополнительную логику, чтобы избежать частых публикаций из CI/CD.
- Рассмотрите возможность использования npm publish –dry-run перед фактической публикацией. Это поможет убедиться, что вы пытаетесь публиковать правильный пакет и не превышаете лимиты.
Заключение
Ваша ошибка 429 скорее всего вызвана частыми попытками публикации. Реализация стратегии повторной попытки и коррекция имени пакета в вашем package.json
помогут решить вашу проблему. Убедитесь также, что вы не превышаете лимиты запросов к NPM, чтобы избежать дальнейших ошибок.