Giao diện
Cấu hình .npmrc (GitLab Registry)
Hướng dẫn chi tiết cấu hình .npmrc để cài (@tasco/*) và publish package lên GitLab Package Registry (gitlab.dnpwater.vn, project tasco/web-framework-core, id 57).
Khái niệm cốt lõi
Một .npmrc cho registry private gồm 2 dòng:
ini
# 1) Scope → registry: package @tasco lấy từ đâu (group endpoint của group `tasco`)
@tasco:registry=https://gitlab.dnpwater.vn/api/v4/groups/tasco/-/packages/npm/
# 2) authToken theo "nerf-dart" (URL không có protocol, bắt đầu bằng //)
//gitlab.dnpwater.vn/api/v4/groups/tasco/-/packages/npm/:_authToken=${NPM_TOKEN}Quy tắc bắt buộc:
- Dòng authToken phải bắt đầu bằng
//(bỏhttp:/https:). Viếthttps://...:_authTokenhoặchttp://...:_authTokenđều sai → npm bỏ qua → request ẩn danh → 401. - Phần host/path của authToken phải khớp với registry đang dùng (cùng host + path).
- Token rỗng cũng cho 401 (ẩn danh). Luôn kiểm tra token có giá trị.
Hai loại endpoint GitLab
| Mục đích | Endpoint | Quyền token |
|---|---|---|
| Cài (install/read) | group-level: …/api/v4/groups/tasco/-/packages/npm/ | read_package_registry |
| Publish (write) | project-level: …/api/v4/projects/<id>/packages/npm/ | write_package_registry |
Không dùng instance-level (
…/api/v4/packages/npm/) để cài: người không phải member của project core nhận 404 (GitLab ẩn package vì thiếu quyền đọc). Scope@tascophải trỏ group endpoint của grouptasco, auth bằng Group Deploy Token scoperead_package_registry— token này dùng chung cả group nên không cần add từng dev vào project core. PAT cá nhân (glpat…) chỉ chạy khi user là member của group/project (role ≥ Reporter).
A. Consumer — cài @tasco/* (team sản phẩm)
Dev local
Project commit sẵn .npmrc (CLI sinh ra):
ini
@tasco:registry=https://gitlab.dnpwater.vn/api/v4/groups/tasco/-/packages/npm/
//gitlab.dnpwater.vn/api/v4/groups/tasco/-/packages/npm/:_authToken=${NPM_TOKEN}Token không commit — đặt biến môi trường NPM_TOKEN, hoặc ghi thẳng vào ~/.npmrc cá nhân:
ini
//gitlab.dnpwater.vn/api/v4/groups/tasco/-/packages/npm/:_authToken=<token>Token là Group Deploy Token (hoặc Group Access Token) của group tasco, scope read_package_registry. PAT cá nhân cũng chạy nhưng chỉ khi user là member của group/project tasco (role ≥ Reporter), nếu không sẽ 404.
CI sản phẩm (.gitlab-ci.yml)
Đặt biến CI/CD NPM_TOKEN (Group Deploy Token scope read_package_registry) — .npmrc commit sẵn đã đọc biến này, nên job chỉ cần:
yaml
before_script:
- pnpm install --frozen-lockfileB. Publish — core CI (đã cấu hình ở .gitlab-ci.yml root)
Publish dùng project-level endpoint + token write. Cấu hình động trong job release:
yaml
release:
before_script:
- corepack enable
- pnpm config set store-dir .pnpm-store
# Cắt MỌI protocol rồi ÉP https (xem gotcha bên dưới).
- |
HOSTPATH="${CI_API_V4_URL#http*://}"
echo "@tasco:registry=https://${HOSTPATH}/projects/${CI_PROJECT_ID}/packages/npm/" >> .npmrc
echo "//${HOSTPATH}/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${NPM_TOKEN}" >> .npmrc
- pnpm install --frozen-lockfile
script:
- pnpm exec turbo run build --filter="./packages/*"
- pnpm changeset publishBiến CI/CD cần đặt (Settings → CI/CD → Variables):
NPM_TOKEN= Deploy Token / Project Access Token scopewrite_package_registry.- Cờ: Masked + Protected (release chạy trên
mainđã là protected branch).
.npmrccho@tasco:registryghi đè khi append — npm/pnpm dùng dòng cuối cùng cho mỗi key, nên dòng project-level (append) thắng dòng group-level (commit sẵn).
Gotcha thực tế (đã gặp khi release 1.0.0)
1. CI_API_V4_URL là http:// → 401
Instance này trả CI_API_V4_URL=http://gitlab.dnpwater.vn/api/v4. Nếu cắt prefix bằng ${CI_API_V4_URL#https:} thì không khớp (http: ≠ https:) → authToken key thành http://…:_authToken (sai) → token không gửi → 401. → Dùng ${CI_API_V4_URL#http*://} (cắt cả http/https) rồi ép https://.
2. CI_JOB_TOKEN bị 401 khi publish
Trên instance này, publish npm bằng CI_JOB_TOKEN bị từ chối. → Dùng access/deploy token (write_package_registry) qua NPM_TOKEN.
3. Protected variable + protected branch
Biến đặt Protected chỉ lộ ra trên nhánh/tag protected. Đảm bảo main là protected branch (đã bật), hoặc bỏ cờ Protected.
4. Read vs Write
Cài cần read_package_registry; publish cần write_package_registry. Dùng nhầm scope → 401/403.
Troubleshooting nhanh
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
401 Unauthorized khi publish | authToken key sai format (có http(s):) hoặc token rỗng/sai scope | Đảm bảo key bắt đầu //, ép https, token write_package_registry |
401 khi install | thiếu token / token chỉ có write | Thêm read_package_registry token vào ~/.npmrc/CI |
404 Not Found khi cài | .npmrc còn trỏ instance-level …/api/v4/packages/npm/, hoặc PAT của user không phải member | Đổi sang group endpoint …/api/v4/groups/tasco/-/packages/npm/ + Group Deploy Token read_package_registry |
404 Not Found khi publish | sai project id / package chưa tồn tại / scope ≠ group | Kiểm tra endpoint + scope @tasco khớp group tasco |
400 ... Version has already been taken | version đã publish | Bump version mới (changeset) |
Token bị "nuốt" do $ | biến CI raw=false + token chứa $ | Bật cờ Expand variable reference = off (raw) cho biến |
Debug an toàn trong CI (không lộ token)
yaml
- 'echo "NPM_TOKEN length: ${#NPM_TOKEN}"' # 0 = chưa inject
- 'grep -v "_authToken" .npmrc || true' # xem registry, ẩn dòng token